1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2016 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 #include "utils.h"
14 #include "score.h"
15 #include "chord.h"
16 #include "measure.h"
17 #include "tie.h"
18 #include "tuplet.h"
19 #include "staff.h"
20 #include "part.h"
21 #include "drumset.h"
22 #include "slur.h"
23 #include "navigate.h"
24 #include "stringdata.h"
25 #include "undo.h"
26 #include "range.h"
27 #include "excerpt.h"
28 #include "accidental.h"
29 
30 namespace Ms {
31 
32 //---------------------------------------------------------
33 //   noteValForPosition
34 //---------------------------------------------------------
35 
noteValForPosition(Position pos,AccidentalType at,bool & error)36 NoteVal Score::noteValForPosition(Position pos, AccidentalType at, bool &error)
37       {
38       error           = false;
39       Segment* s      = pos.segment;
40       int line        = pos.line;
41       Fraction tick   = s->tick();
42       int staffIdx    = pos.staffIdx;
43       Staff* st       = staff(staffIdx);
44       ClefType clef   = st->clef(tick);
45       const Instrument* instr = st->part()->instrument(s->tick());
46       NoteVal nval;
47       const StringData* stringData = 0;
48 
49       // pitched/unpitched note entry depends on instrument (override StaffGroup)
50       StaffGroup staffGroup = st->staffType(tick)->group();
51       if (staffGroup != StaffGroup::TAB)
52             staffGroup = instr->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
53 
54       switch (staffGroup) {
55             case StaffGroup::PERCUSSION: {
56                   if (_is.rest())
57                         break;
58                   const Drumset* ds = instr->drumset();
59                   nval.pitch        = _is.drumNote();
60                   if (nval.pitch < 0) {
61                         error = true;
62                         return nval;
63                         }
64                   nval.headGroup = ds->noteHead(nval.pitch);
65                   if (nval.headGroup == NoteHead::Group::HEAD_INVALID) {
66                         error = true;
67                         return nval;
68                         }
69                   break;
70                   }
71             case StaffGroup::TAB: {
72                   if (_is.rest()) {
73                         error = true;
74                         return nval;
75                         }
76                   stringData = instr->stringData();
77                   line = st->staffType(tick)->visualStringToPhys(line);
78                   if (line < 0 || line >= stringData->strings()) {
79                         error = true;
80                         return nval;
81                         }
82                   // build a default NoteVal for that string
83                   nval.string = line;
84                   if (pos.fret != FRET_NONE)          // if a fret is given, use it
85                         nval.fret = pos.fret;
86                   else {                              // if no fret, use 0 as default
87                         _is.setString(line);
88                         nval.fret = 0;
89                         }
90                   // reduce within fret limit
91                   if (nval.fret > stringData->frets())
92                         nval.fret = stringData->frets();
93                   // for open strings, only accepts fret 0 (strings in StringData are from bottom to top)
94                   int   strgDataIdx = stringData->strings() - line - 1;
95                   if (nval.fret > 0 && stringData->stringList().at(strgDataIdx).open == true)
96                         nval.fret = 0;
97                   nval.pitch = stringData->getPitch(line, nval.fret, st, tick);
98                   break;
99                   }
100 
101             case StaffGroup::STANDARD: {
102                   AccidentalVal acci = (at == AccidentalType::NONE ? s->measure()->findAccidental(s, staffIdx, line, error) : Accidental::subtype2value(at));
103                   if (error)
104                         return nval;
105                   int step           = absStep(line, clef);
106                   int octave         = step/7;
107                   nval.pitch         = step2pitch(step) + octave * 12 + int(acci);
108                   if (styleB(Sid::concertPitch))
109                         nval.tpc1 = step2tpc(step % 7, acci);
110                   else {
111                         nval.pitch += instr->transpose().chromatic;
112                         nval.tpc2 = step2tpc(step % 7, acci);
113                         Interval v = st->part()->instrument(tick)->transpose();
114                         if (v.isZero())
115                               nval.tpc1 = nval.tpc2;
116                         else
117                               nval.tpc1 = Ms::transposeTpc(nval.tpc2, v, true);
118                         }
119                   }
120                   break;
121             }
122       return nval;
123       }
124 
125 //---------------------------------------------------------
126 //   addPitch
127 //---------------------------------------------------------
128 
addPitch(NoteVal & nval,bool addFlag,InputState * externalInputState)129 Note* Score::addPitch(NoteVal& nval, bool addFlag, InputState* externalInputState)
130       {
131       InputState& is = externalInputState ? (*externalInputState) : _is;
132 
133       if (addFlag) {
134             ChordRest* c = toChordRest(is.lastSegment()->element(is.track()));
135 
136             if (c == 0 || !c->isChord()) {
137                   qDebug("Score::addPitch: cr %s", c ? c->name() : "zero");
138                   return 0;
139                   }
140             Note* note = addNote(toChord(c), nval, /* forceAccidental */ false, externalInputState);
141             if (is.lastSegment() == is.segment()) {
142                   NoteEntryMethod entryMethod = is.noteEntryMethod();
143                   if (entryMethod != NoteEntryMethod::REALTIME_AUTO && entryMethod != NoteEntryMethod::REALTIME_MANUAL)
144                         is.moveToNextInputPos();
145                   }
146             return note;
147             }
148       expandVoice(is.segment(), is.track());
149 
150       // insert note
151       Direction stemDirection = Direction::AUTO;
152       int track               = is.track();
153       if (is.drumNote() != -1) {
154             nval.pitch        = is.drumNote();
155             const Drumset* ds = is.drumset();
156             nval.headGroup    = ds->noteHead(nval.pitch);
157             stemDirection     = ds->stemDirection(nval.pitch);
158             track             = ds->voice(nval.pitch) + (is.track() / VOICES) * VOICES;
159             is.setTrack(track);
160             expandVoice(is.segment(), is.track());
161             }
162       if (!is.cr())
163             return 0;
164       Fraction duration;
165       if (is.usingNoteEntryMethod(NoteEntryMethod::REPITCH)) {
166             duration = is.cr()->ticks();
167             }
168       else if (is.usingNoteEntryMethod(NoteEntryMethod::REALTIME_AUTO) || is.usingNoteEntryMethod(NoteEntryMethod::REALTIME_MANUAL)) {
169             // FIXME: truncate duration at barline in real-time modes.
170             //   The user might try to enter a duration that is too long to fit in the remaining space in the measure.
171             //   We could split the duration at the barline and continue into the next bar, but this would create extra
172             //   notes, extra ties, and extra pain. Instead, we simply truncate the duration at the barline.
173             Fraction ticks2measureEnd = is.segment()->measure()->ticks() - is.segment()->rtick();
174             duration = is.duration() > ticks2measureEnd ? ticks2measureEnd : is.duration().fraction();
175             }
176       else {
177             duration = is.duration().fraction();
178             }
179       Note* note = 0;
180       Note* firstTiedNote = 0;
181       Note* lastTiedNote = 0;
182       if (is.usingNoteEntryMethod(NoteEntryMethod::REPITCH) && is.cr()->isChord()) {
183             // repitch mode for MIDI input (where we are given a pitch) is handled here
184             // for keyboard input (where we are given a staff position), there is a separate function Score::repitchNote()
185             // the code is similar enough that it could possibly be refactored
186             Chord* chord = toChord(is.cr());
187             note = new Note(this);
188             note->setParent(chord);
189             note->setTrack(chord->track());
190             note->setNval(nval);
191             lastTiedNote = note;
192             if (!addFlag) {
193                   std::vector<Note*> notes = chord->notes();
194                   // break all ties into current chord
195                   // these will exist only if user explicitly moved cursor to a tied-into note
196                   // in ordinary use, cursor will autoamtically skip past these during note entry
197                   for (Note* n : notes) {
198                         if (n->tieBack())
199                               undoRemoveElement(n->tieBack());
200                         }
201                   // for single note chords only, preserve ties by changing pitch of all forward notes
202                   // the tie forward itself will be added later
203                   // multi-note chords get reduced to single note chords anyhow since we remove the old notes below
204                   // so there will be no way to preserve those ties
205                   if (notes.size() == 1 && notes.front()->tieFor()) {
206                         Note* tn = notes.front()->tieFor()->endNote();
207                         while (tn) {
208                               Chord* tc = tn->chord();
209                               if (tc->notes().size() != 1) {
210                                     undoRemoveElement(tn->tieBack());
211                                     break;
212                                     }
213                               if (!firstTiedNote)
214                                     firstTiedNote = tn;
215                               lastTiedNote = tn;
216                               undoChangePitch(tn, note->pitch(), note->tpc1(), note->tpc2());
217                               if (tn->tieFor())
218                                     tn = tn->tieFor()->endNote();
219                               else
220                                     break;
221                               }
222                         }
223                   // remove all notes from chord
224                   // the new note will be added below
225                   while (!chord->notes().empty())
226                         undoRemoveElement(chord->notes().front());
227                   }
228             // add new note to chord
229             undoAddElement(note);
230             setPlayNote(true);
231             // recreate tie forward if there is a note to tie to
232             // one-sided ties will not be recreated
233             if (firstTiedNote) {
234                   Tie* tie = new Tie(this);
235                   tie->setStartNote(note);
236                   tie->setEndNote(firstTiedNote);
237                   tie->setTick(tie->startNote()->tick());
238                   tie->setTick2(tie->endNote()->tick());
239                   tie->setTrack(note->track());
240                   undoAddElement(tie);
241                   }
242             select(lastTiedNote);
243             }
244       else if (!is.usingNoteEntryMethod(NoteEntryMethod::REPITCH)) {
245             Segment* seg = setNoteRest(is.segment(), track, nval, duration, stemDirection, /* forceAccidental */ false, /* rhythmic */ false, externalInputState);
246             if (seg) {
247                   note = toChord(seg->element(track))->upNote();
248                   }
249             }
250 
251       if (is.slur()) {
252             //
253             // extend slur
254             //
255             ChordRest* e = searchNote(is.tick(), is.track());
256             if (e) {
257                   Fraction stick = Fraction(0, 1);
258                   Element* ee = is.slur()->startElement();
259                   if (ee->isChordRest())
260                         stick = toChordRest(ee)->tick();
261                   else if (ee->isNote())
262                         stick = toNote(ee)->chord()->tick();
263                   if (stick == e->tick()) {
264                         is.slur()->setTick(stick);
265                         is.slur()->setStartElement(e);
266                         }
267                   else {
268                         is.slur()->setTick2(e->tick());
269                         is.slur()->setEndElement(e);
270                         }
271                   }
272             else
273                   qDebug("addPitch: cannot find slur note");
274             }
275       if (is.usingNoteEntryMethod(NoteEntryMethod::REPITCH)) {
276             // move cursor to next note, but skip tied notes (they were already repitched above)
277             ChordRest* next = lastTiedNote ? nextChordRest(lastTiedNote->chord()) : nextChordRest(is.cr());
278             while (next && !next->isChord())
279                   next = nextChordRest(next);
280             if (next)
281                   is.moveInputPos(next->segment());
282             }
283       else {
284             NoteEntryMethod entryMethod = is.noteEntryMethod();
285             if (entryMethod != NoteEntryMethod::REALTIME_AUTO && entryMethod != NoteEntryMethod::REALTIME_MANUAL)
286                   is.moveToNextInputPos();
287             }
288       return note;
289       }
290 
291 //---------------------------------------------------------
292 //   putNote
293 //    mouse click in state NoteType::ENTRY
294 //---------------------------------------------------------
295 
putNote(const QPointF & pos,bool replace,bool insert)296 void Score::putNote(const QPointF& pos, bool replace, bool insert)
297       {
298       Position p;
299       if (!getPosition(&p, pos, _is.voice())) {
300             qDebug("cannot put note here, get position failed");
301             return;
302             }
303       Score* score = p.segment->score();
304       // it is not safe to call Score::repitchNote() if p is on a TAB staff
305       bool isTablature = staff(p.staffIdx)->isTabStaff(p.segment->tick());
306 
307       //  calculate actual clicked line from staffType offset and stepOffset
308       Staff* ss = score->staff(p.staffIdx);
309       int stepOffset = ss->staffType(p.segment->tick())->stepOffset();
310       qreal stYOffset = ss->staffType(p.segment->tick())->yoffset().val();
311       qreal lineDist = ss->staffType(p.segment->tick())->lineDistance().val();
312       p.line -= stepOffset + 2 * stYOffset / lineDist;
313 
314       if (score->inputState().usingNoteEntryMethod(NoteEntryMethod::REPITCH) && !isTablature)
315             score->repitchNote(p, replace);
316       else {
317             if (insert
318                || score->inputState().usingNoteEntryMethod(NoteEntryMethod::TIMEWISE))
319                   score->insertChord(p);
320             else
321                   score->putNote(p, replace);
322             }
323       }
324 
putNote(const Position & p,bool replace)325 void Score::putNote(const Position& p, bool replace)
326       {
327       Staff* st   = staff(p.staffIdx);
328       Segment* s  = p.segment;
329 
330       _is.setTrack(p.staffIdx * VOICES + _is.voice());
331       _is.setSegment(s);
332 
333       if (score()->excerpt() && !score()->excerpt()->tracks().isEmpty() && score()->excerpt()->tracks().key(_is.track(), -1) == -1)
334             return;
335 
336       Direction stemDirection = Direction::AUTO;
337       bool error;
338       NoteVal nval = noteValForPosition(p, _is.accidentalType(), error);
339       if (error)
340             return;
341 
342       const StringData* stringData = 0;
343 
344       // pitched/unpitched note entry depends on instrument (override StaffGroup)
345       StaffGroup staffGroup = st->staffType(s->tick())->group();
346       if (staffGroup != StaffGroup::TAB)
347             staffGroup = st->part()->instrument(s->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
348 
349       switch (staffGroup) {
350             case StaffGroup::PERCUSSION: {
351                   const Drumset* ds = st->part()->instrument(s->tick())->drumset();
352                   stemDirection     = ds->stemDirection(nval.pitch);
353                   break;
354                   }
355             case StaffGroup::TAB:
356                   stringData = st->part()->instrument(s->tick())->stringData();
357                   _is.setDrumNote(-1);
358                   break;
359             case StaffGroup::STANDARD:
360                   _is.setDrumNote(-1);
361                   break;
362             }
363 
364       expandVoice();
365       ChordRest* cr = _is.cr();
366       bool addToChord = false;
367 
368       if (cr) {
369             // retrieve total duration of current chord
370             TDuration d = cr->durationType();
371             // if not in replace mode AND chord duration == input duration AND not rest input
372             // we need to add to current chord (otherwise, we will need to replace it or create a new one)
373             if (!replace
374                && (d == _is.duration())
375                && cr->isChord()
376                && !_is.rest())
377                   {
378                   if (st->isTabStaff(cr->tick())) {      // TAB
379                         // if a note on same string already exists, update to new pitch/fret
380                         foreach (Note* note, toChord(cr)->notes())
381                               if (note->string() == nval.string) {       // if string is the same
382                                     // if adding a new digit will keep fret number within fret limit,
383                                     // add a digit to existing fret number
384                                     if (stringData) {
385                                           int fret = note->fret() * 10 + nval.fret;
386                                           if (fret <= stringData->frets() ) {
387                                                 nval.fret = fret;
388                                                 nval.pitch = stringData->getPitch(nval.string, nval.fret, st, s->tick());
389                                                 }
390                                           else
391                                                 qDebug("can't increase fret to %d", fret);
392                                           }
393                                     // set fret number (original or combined) in all linked notes
394                                     int tpc1 = note->tpc1default(nval.pitch);
395                                     int tpc2 = note->tpc2default(nval.pitch);
396                                     undoChangeFretting(note, nval.pitch, nval.string, nval.fret, tpc1, tpc2);
397                                     setPlayNote(true);
398                                     return;
399                                     }
400                         }
401                   else {                        // not TAB
402                         // if a note with the same pitch already exists in the chord, remove it
403                         Chord* chord = toChord(cr);
404                         Note* note = chord->findNote(nval.pitch);
405                         if (note) {
406                               if (chord->notes().size() > 1)
407                                     undoRemoveElement(note);
408                               return;
409                               }
410                         }
411                   addToChord = true;            // if no special case, add note to chord
412                   }
413             }
414       bool forceAccidental = false;
415       if (_is.accidentalType() != AccidentalType::NONE) {
416             NoteVal nval2 = noteValForPosition(p, AccidentalType::NONE, error);
417             forceAccidental = (nval.pitch == nval2.pitch);
418             }
419       if (addToChord && cr->isChord()) {
420             // if adding, add!
421             addNote(toChord(cr), nval, forceAccidental);
422             _is.setAccidentalType(AccidentalType::NONE);
423             return;
424             }
425       else {
426             // if not adding, replace current chord (or create a new one)
427 
428             if (_is.rest())
429                   nval.pitch = -1;
430             setNoteRest(_is.segment(), _is.track(), nval, _is.duration().fraction(), stemDirection, forceAccidental);
431             _is.setAccidentalType(AccidentalType::NONE);
432             }
433       if (!st->isTabStaff(cr->tick()))
434             _is.moveToNextInputPos();
435       }
436 
437 //---------------------------------------------------------
438 //   repitchNote
439 //---------------------------------------------------------
440 
repitchNote(const Position & p,bool replace)441 void Score::repitchNote(const Position& p, bool replace)
442       {
443       Segment* s      = p.segment;
444       Fraction tick   = s->tick();
445       Staff* st       = staff(p.staffIdx);
446       ClefType clef   = st->clef(tick);
447 
448       NoteVal nval;
449       bool error = false;
450       AccidentalType at = _is.accidentalType();
451       if (_is.drumset() && _is.drumNote() != -1) {
452             nval.pitch = _is.drumNote();
453             }
454       else {
455             AccidentalVal acci = (at == AccidentalType::NONE ? s->measure()->findAccidental(s, p.staffIdx, p.line, error) : Accidental::subtype2value(at));
456             if (error)
457                   return;
458             int step   = absStep(p.line, clef);
459             int octave = step / 7;
460             nval.pitch = step2pitch(step) + octave * 12 + int(acci);
461 
462             if (styleB(Sid::concertPitch))
463                   nval.tpc1 = step2tpc(step % 7, acci);
464             else {
465                   nval.pitch += st->part()->instrument(s->tick())->transpose().chromatic;
466                   nval.tpc2 = step2tpc(step % 7, acci);
467                   }
468             }
469 
470       if (!_is.segment())
471             return;
472 
473       Chord* chord;
474       ChordRest* cr = _is.cr();
475       if (!cr) {
476             cr = _is.segment()->nextChordRest(_is.track());
477             if (!cr)
478                   return;
479             }
480       if (cr->isRest()) { //skip rests
481             ChordRest* next = nextChordRest(cr);
482             while(next && !next->isChord())
483                   next = nextChordRest(next);
484             if (next)
485                   _is.moveInputPos(next->segment());
486             return;
487             }
488       else {
489             chord = toChord(cr);
490             }
491       Note* note = new Note(this);
492       note->setParent(chord);
493       note->setTrack(chord->track());
494       note->setNval(nval);
495 
496       Note* firstTiedNote = 0;
497       Note* lastTiedNote = note;
498       if (replace) {
499             std::vector<Note*> notes = chord->notes();
500             // break all ties into current chord
501             // these will exist only if user explicitly moved cursor to a tied-into note
502             // in ordinary use, cursor will autoamtically skip past these during note entry
503             for (Note* n : notes) {
504                   if (n->tieBack())
505                         undoRemoveElement(n->tieBack());
506                   }
507             // for single note chords only, preserve ties by changing pitch of all forward notes
508             // the tie forward itself will be added later
509             // multi-note chords get reduced to single note chords anyhow since we remove the old notes below
510             // so there will be no way to preserve those ties
511             if (notes.size() == 1 && notes.front()->tieFor()) {
512                   Note* tn = notes.front()->tieFor()->endNote();
513                   while (tn) {
514                         Chord* tc = tn->chord();
515                         if (tc->notes().size() != 1) {
516                               undoRemoveElement(tn->tieBack());
517                               break;
518                               }
519                         if (!firstTiedNote)
520                               firstTiedNote = tn;
521                         lastTiedNote = tn;
522                         undoChangePitch(tn, note->pitch(), note->tpc1(), note->tpc2());
523                         if (tn->tieFor())
524                               tn = tn->tieFor()->endNote();
525                         else
526                               break;
527                         }
528                   }
529             // remove all notes from chord
530             // the new note will be added below
531             while (!chord->notes().empty())
532                   undoRemoveElement(chord->notes().front());
533       }
534       // add new note to chord
535       undoAddElement(note);
536       bool forceAccidental = false;
537       if (_is.accidentalType() != AccidentalType::NONE) {
538             NoteVal nval2 = noteValForPosition(p, AccidentalType::NONE, error);
539             forceAccidental = (nval.pitch == nval2.pitch);
540             }
541       if (forceAccidental) {
542             int tpc = styleB(Sid::concertPitch) ? nval.tpc1 : nval.tpc2;
543             AccidentalVal alter = tpc2alter(tpc);
544             at = Accidental::value2subtype(alter);
545             Accidental* a = new Accidental(this);
546             a->setAccidentalType(at);
547             a->setRole(AccidentalRole::USER);
548             a->setParent(note);
549             undoAddElement(a);
550             }
551       setPlayNote(true);
552       setPlayChord(true);
553       // recreate tie forward if there is a note to tie to
554       // one-sided ties will not be recreated
555       if (firstTiedNote) {
556             Tie* tie = new Tie(this);
557             tie->setStartNote(note);
558             tie->setEndNote(firstTiedNote);
559             tie->setTick(tie->startNote()->tick());
560             tie->setTick2(tie->endNote()->tick());
561             tie->setTrack(note->track());
562             undoAddElement(tie);
563             }
564       select(lastTiedNote);
565       // move to next Chord
566       ChordRest* next = nextChordRest(lastTiedNote->chord());
567       while (next && !next->isChord())
568             next = nextChordRest(next);
569       if (next)
570             _is.moveInputPos(next->segment());
571       }
572 
573 //---------------------------------------------------------
574 //   insertChord
575 //---------------------------------------------------------
576 
insertChord(const Position & pos)577 void Score::insertChord(const Position& pos)
578       {
579       // insert
580       // TODO:
581       //    - check voices
582       //    - split chord/rest
583 
584       Element* el = selection().element();
585       if (!el || !(el->isNote() || el->isRest()))
586             return;
587       Segment* seg = pos.segment;
588       if (seg->splitsTuplet()) {
589             MScore::setError(CANNOT_INSERT_TUPLET);
590             return;
591             }
592       if (_is.insertMode())
593             globalInsertChord(pos);
594       else
595             localInsertChord(pos);
596       }
597 
598 //---------------------------------------------------------
599 //   localInsertChord
600 //---------------------------------------------------------
601 
localInsertChord(const Position & pos)602 void Score::localInsertChord(const Position& pos)
603       {
604       const TDuration duration = _is.duration();
605       const Fraction fraction  = duration.fraction();
606       const Fraction len       = fraction;
607       Segment* seg             = pos.segment;
608       Fraction tick            = seg->tick();
609       Measure* measure         = seg->measure()->isMMRest() ? seg->measure()->mmRestFirst() : seg->measure();
610       const Fraction targetMeasureLen = measure->ticks() + fraction;
611 
612       // Shift spanners, enlarge the measure.
613       // The approach is similar to that in Measure::adjustToLen() but does
614       // insert time to the middle of the measure rather than to the end.
615       undoInsertTime(tick, len);
616       undo(new InsertTime(this, tick, len));
617 
618       for (Score* score : scoreList()) {
619             Measure* m = score->tick2measure(tick);
620             undo(new ChangeMeasureLen(m, targetMeasureLen));
621             Segment* scoreSeg = m->tick2segment(tick);
622             for (Segment* s = scoreSeg; s; s = s->next())
623                   s->undoChangeProperty(Pid::TICK, s->rtick() + len);
624             }
625 
626       // Fill the inserted time with rests.
627       // This is better to be done in master score to cover all staves.
628       MasterScore* ms = masterScore();
629       Measure* msMeasure = ms->tick2measure(tick);
630       const int msTracks = ms->ntracks();
631 
632       Segment* firstSeg = msMeasure->first(SegmentType::ChordRest);
633       for (int track = 0; track < msTracks; ++track) {
634             Element* maybeRest = firstSeg->element(track);
635             bool measureIsFull = false;
636 
637             // I. Convert any measure rests into normal (non-measure) rest(s) of equivalent duration
638             if (maybeRest && maybeRest->isRest() && toRest(maybeRest)->durationType().isMeasure()) {
639                   ms->undoRemoveElement(maybeRest);
640                   Rest* measureRest = toRest(maybeRest);
641                   // If measure rest is situated at measure start we will fill
642                   // the whole measure with rests.
643                   measureIsFull = measureRest->rtick().isZero();
644                   const Fraction fillLen = measureIsFull ? targetMeasureLen : measureRest->ticks();
645                   ms->setRest(measureRest->tick(), track, fillLen, /* useDots */ false, /* tuplet */ nullptr, /* useFullMeasureRest */ false);
646                   }
647 
648             // II. Make chord or rest in other track longer if it crosses the insert area
649             if (!measureIsFull) {
650                   ChordRest* cr = ms->findCR(tick, track);
651                   if (cr && cr->tick() < tick && (cr->tick() + cr->actualTicks()) > tick) {
652                         if (cr->isRest()) {
653                               const Fraction fillLen = cr->ticks() + fraction;
654                               ms->undoRemoveElement(cr);
655                               ms->setRest(cr->tick(), track, fillLen, /* useDots */ false, /* tuplet */ nullptr, /* useFullMeasureRest */ false);
656                               }
657                         else if (cr->isChord()) {
658                               Chord* chord = toChord(cr);
659                               std::vector<TDuration> durations = toDurationList(chord->ticks() + fraction, /* useDots */ true);
660                               Fraction p = chord->tick();
661                               ms->undoRemoveElement(chord);
662                               Chord* prevChord = nullptr;
663                               for (const TDuration& dur : durations) {
664                                     Chord* prototype = prevChord ? prevChord : chord;
665                                     const bool genTie = bool(prevChord);
666                                     prevChord = ms->addChord(p, dur, prototype, genTie, /* tuplet */ nullptr);
667                                     p += dur.fraction();
668                                     }
669                               // TODO: reconnect ties if this chord was tied to other
670                               }
671                         measureIsFull = true;
672                         }
673                   }
674 
675             // III. insert rest(s) to fill the inserted space
676             if (!measureIsFull && msMeasure->hasVoice(track))
677                   ms->setRest(tick, track, fraction, /* useDots */ false, /* tuplet */ nullptr);
678             }
679 
680       // Put the note itself.
681       Segment* s = measure->undoGetSegment(SegmentType::ChordRest, tick);
682       Position p(pos);
683       p.segment = s;
684       putNote(p, true);
685       }
686 
687 //---------------------------------------------------------
688 //   globalInsertChord
689 //---------------------------------------------------------
690 
globalInsertChord(const Position & pos)691 void Score::globalInsertChord(const Position& pos)
692       {
693       ChordRest* cr = selection().cr();
694       int track = cr ? cr->track() : -1;
695       deselectAll();
696       Segment* s1        = pos.segment;
697       Segment* s2        = lastSegment();
698       TDuration duration = _is.duration();
699       Fraction fraction  = duration.fraction();
700       ScoreRange r;
701 
702       r.read(s1, s2, false);
703 
704       int strack = 0;                      // for now for all tracks
705       int etrack = nstaves() * VOICES;
706       Fraction stick  = s1->tick();
707       Fraction etick  = s2->tick();
708       Fraction ticks  = fraction;
709       Fraction len    = r.ticks();
710 
711       if (!r.truncate(fraction))
712             appendMeasures(1);
713 
714       putNote(pos, true);
715       Fraction dtick = s1->tick() + ticks;
716       int voiceOffsets[VOICES] { 0, 0, 0, 0 };
717       len = r.ticks();
718       for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx)
719             makeGap1(dtick, staffIdx, r.ticks(), voiceOffsets);
720       r.write(this, dtick);
721 
722       for (auto i :  spanner()) {
723             Spanner* s = i.second;
724             if (s->track() >= strack && s->track() < etrack) {
725                   if (s->tick() >= stick && s->tick() < etick)
726                         s->undoChangeProperty(Pid::SPANNER_TICK, s->tick() + ticks);
727                   else if (s->tick2() >= stick && s->tick2() < etick)
728                         s->undoChangeProperty(Pid::SPANNER_TICKS, s->ticks() + ticks);
729                   }
730             }
731 
732       if (track != -1) {
733             Measure* m = tick2measure(dtick);
734             Segment* s = m->findSegment(SegmentType::ChordRest, dtick);
735             Element* e = s->element(track);
736             if (e)
737                   select(e->isChord() ? toChord(e)->notes().front() : e);
738             }
739       }
740 
741 
742 } // namespace Ms
743 
744