Segment* Score::tick2segmentEnd(int track, int tick) const { Measure* m = tick2measure(tick); if (m == 0) { qDebug("tick2segment(): not found tick %d", tick); return 0; } // loop over all segments for (Segment* segment = m->first(Segment::Type::ChordRest); segment; segment = segment->next(Segment::Type::ChordRest)) { ChordRest* cr = toChordRest(segment->element(track)); if (!cr) continue; // TODO LVI: check if following is correct, see exceptions in // ExportMusicXml::chord() and ExportMusicXml::rest() int endTick = cr->tick() + cr->actualTicks(); if (endTick < tick) continue; // not found yet else if (endTick == tick) { return segment; // found it } else { // endTick > tick (beyond the tick we are looking for) return 0; } } return 0; }
void Cursor::add(Element* s) { if (!_segment) return; s->setTrack(_track); s->setParent(_segment); if (s->isChordRest()) s->score()->undoAddCR(toChordRest(s), _segment->measure(), _segment->tick()); else if (s->type() == ElementType::KEYSIG) { Segment* ns = _segment->measure()->undoGetSegment(SegmentType::KeySig, _segment->tick()); s->setParent(ns); score()->undoAddElement(s); } else if (s->type() == ElementType::TIMESIG) { Measure* m = _segment->measure(); int tick = m->tick(); score()->cmdAddTimeSig(m, _track, toTimeSig(s), false); m = score()->tick2measure(tick); _segment = m->first(_filter); nextInTrack(); } else if (s->type() == ElementType::LAYOUT_BREAK) { Measure* m = _segment->measure(); s->setParent(m); score()->undoAddElement(s); } else { score()->undoAddElement(s); } score()->setLayoutAll(); }
void ScoreView::lyricsEndEdit() { Lyrics* lyrics = toLyrics(editData.element); // if not empty, make sure this new lyrics does not fall in the middle // of an existing melisma from a previous lyrics; in case, shorten it int verse = lyrics->no(); Placement placement = lyrics->placement(); int track = lyrics->track(); // search previous lyric Lyrics* prevLyrics = 0; Segment* prevSegment = lyrics->segment()->prev1(SegmentType::ChordRest); Segment* segment = prevSegment; while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (cr) { prevLyrics = cr->lyrics(verse, placement); if (prevLyrics) break; } segment = segment->prev1(SegmentType::ChordRest); } if (prevLyrics && prevLyrics->syllabic() == Lyrics::Syllabic::END) { int endTick = prevSegment->tick(); // a prev. melisma should not go beyond this segment if (prevLyrics->endTick() >= endTick) prevLyrics->undoChangeProperty(Pid::LYRIC_TICKS, endTick - prevLyrics->segment()->tick()); } }
void Cursor::add(Element* wrapped) { Ms::Element* s = wrapped->element(); if (!_segment || !s) return; wrapped->setOwnership(Ownership::SCORE); s->setTrack(_track); s->setParent(_segment); if (s->isChordRest()) s->score()->undoAddCR(toChordRest(s), _segment->measure(), _segment->tick()); else if (s->type() == ElementType::KEYSIG) { Ms::Segment* ns = _segment->measure()->undoGetSegment(SegmentType::KeySig, _segment->tick()); s->setParent(ns); _score->undoAddElement(s); } else if (s->type() == ElementType::TIMESIG) { Ms::Measure* m = _segment->measure(); Fraction tick = m->tick(); _score->cmdAddTimeSig(m, _track, toTimeSig(s), false); m = _score->tick2measure(tick); _segment = m->first(_filter); nextInTrack(); } else if (s->type() == ElementType::LAYOUT_BREAK) { Ms::Measure* m = _segment->measure(); s->setParent(m); _score->undoAddElement(s); } else { _score->undoAddElement(s); } _score->setLayoutAll(); }
Segment* skipTuplet(Tuplet* tuplet) { DurationElement* nde = tuplet->elements().back(); while (nde->isTuplet()) { tuplet = toTuplet(nde); nde = tuplet->elements().back(); } return toChordRest(nde)->segment(); }
int Part::lyricCount() { if (!score()) return 0; int count = 0; Segment::Type st = Segment::Type::ChordRest; for (Segment* seg = score()->firstMeasure()->first(st); seg; seg = seg->next1(st)) { for (int i = startTrack(); i < endTrack() ; ++i) { ChordRest* cr = toChordRest(seg->element(i)); if (cr) count += cr->lyrics().size(); } } return count; }
void InputState::moveInputPos(Element* e) { if (e == 0) return; Segment* s; if (e->isChordRest1()) s = toChordRest(e)->segment(); else s = toSegment(e); if (s->isSegment()) { if (s->measure()->isMMRest()) { Measure* m = s->measure()->mmRestFirst(); s = m->findSegment(Segment::Type::ChordRest, m->tick()); } _lastSegment = _segment; _segment = s; } }
static Lyrics* searchNextLyrics(Segment* s, int staffIdx, int verse, Placement p) { Lyrics* l = 0; while ((s = s->next1(SegmentType::ChordRest))) { int strack = staffIdx * VOICES; int etrack = strack + VOICES; // search through all tracks of current staff looking for a lyric in specified verse for (int track = strack; track < etrack; ++track) { ChordRest* cr = toChordRest(s->element(track)); if (cr) { // cr with lyrics found, but does it have a syllable in specified verse? l = cr->lyrics(verse, p); if (l) break; } } if (l) break; } return l; }
void ScoreView::lyricsUnderscore() { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); PropertyFlags pFlags = lyrics->propertyFlags(Pid::PLACEMENT); int endTick = segment->tick(); // a previous melisma cannot extend beyond this point changeState(ViewState::NORMAL); // search next chord Segment* nextSegment = segment; while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } // look for the lyrics we are moving from; may be the current lyrics or a previous one // we are extending with several underscores Lyrics* fromLyrics = 0; while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (cr) { fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; } segment = segment->prev1(SegmentType::ChordRest); // if the segment has a rest in this track, stop going back Element* e = segment ? segment->element(track) : 0; if (e && !e->isChord()) break; } // one-chord melisma? // if still at melisma initial chord and there is a valid next chord (if not, // there will be no melisma anyway), set a temporary melisma duration if (fromLyrics == lyrics && nextSegment) { _score->startCmd(); lyrics->undoChangeProperty(Pid::LYRIC_TICKS, Lyrics::TEMP_MELISMA_TICKS); _score->setLayoutAll(); _score->endCmd(); } if (nextSegment == 0) { _score->startCmd(); if (fromLyrics) { switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; default: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } if (fromLyrics->segment()->tick() < endTick) fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, endTick - fromLyrics->segment()->tick()); } // leave edit mode, select something (just for user feedback) and update to show extended melisam mscore->changeState(STATE_NORMAL); if (fromLyrics) _score->select(fromLyrics, SelectType::SINGLE, 0); _score->setLayoutAll(); _score->endCmd(); return; } // if a place for a new lyrics has been found, create a lyrics there ChordRest* cr = toChordRest(nextSegment->element(track)); Lyrics* toLyrics = cr->lyrics(verse, placement); bool newLyrics = (toLyrics == 0); if (!toLyrics) { toLyrics = new Lyrics(_score); toLyrics->setTrack(track); toLyrics->setParent(nextSegment->element(track)); toLyrics->setNo(verse); toLyrics->setPlacement(placement); toLyrics->setPropertyFlags(Pid::PLACEMENT, pFlags); toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE); } // as we arrived at toLyrics by an underscore, it cannot have syllabic dashes before else if (toLyrics->syllabic() == Lyrics::Syllabic::MIDDLE) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); else if (toLyrics->syllabic() == Lyrics::Syllabic::END) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); if (fromLyrics) { // as we moved away from fromLyrics by an underscore, // it can be isolated or terminal but cannot have dashes after switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; default: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } // for the same reason, if it has a melisma, this cannot extend beyond toLyrics if (fromLyrics->segment()->tick() < endTick) fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, endTick - fromLyrics->segment()->tick()); } if (newLyrics) _score->undoAddElement(toLyrics); _score->endCmd(); _score->select(toLyrics, SelectType::SINGLE, 0); startEdit(toLyrics, Grip::NO_GRIP); adjustCanvasPosition(toLyrics, false); TextCursor* cursor = Ms::toLyrics(editData.element)->cursor(editData); Ms::toLyrics(editData.element)->selectAll(cursor); }
void ScoreView::lyricsMinus() { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); PropertyFlags pFlags = lyrics->propertyFlags(Pid::PLACEMENT); changeState(ViewState::NORMAL); // search next chord Segment* nextSegment = segment; while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } if (nextSegment == 0) return; // look for the lyrics we are moving from; may be the current lyrics or a previous one // we are extending with several dashes Lyrics* fromLyrics = 0; while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (!cr) { segment = segment->prev1(SegmentType::ChordRest); continue; } fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; segment = segment->prev1(SegmentType::ChordRest); } _score->startCmd(); ChordRest* cr = toChordRest(nextSegment->element(track)); Lyrics* toLyrics = cr->lyrics(verse, placement); bool newLyrics = (toLyrics == 0); if (!toLyrics) { toLyrics = new Lyrics(_score); toLyrics->setTrack(track); toLyrics->setParent(nextSegment->element(track)); toLyrics->setNo(verse); toLyrics->setPlacement(placement); toLyrics->setPropertyFlags(Pid::PLACEMENT, pFlags); toLyrics->setSyllabic(Lyrics::Syllabic::END); } else { // as we arrived at toLyrics by a dash, it cannot be initial or isolated if (toLyrics->syllabic() == Lyrics::Syllabic::BEGIN) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::MIDDLE)); else if (toLyrics->syllabic() == Lyrics::Syllabic::SINGLE) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); } if (fromLyrics) { // as we moved away from fromLyrics by a dash, // it can have syll. dashes before and after but cannot be isolated or terminal switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::BEGIN: case Lyrics::Syllabic::MIDDLE: break; case Lyrics::Syllabic::SINGLE: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); break; case Lyrics::Syllabic::END: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::MIDDLE)); break; } // for the same reason, it cannot have a melisma fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, 0); } if (newLyrics) _score->undoAddElement(toLyrics); _score->endCmd(); _score->select(toLyrics, SelectType::SINGLE, 0); startEdit(toLyrics, Grip::NO_GRIP); adjustCanvasPosition(toLyrics, false); TextCursor* cursor = Ms::toLyrics(editData.element)->cursor(editData); Ms::toLyrics(editData.element)->selectAll(cursor); _score->setLayoutAll(); }
void ScoreView::lyricsTab(bool back, bool end, bool moveOnly) { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); PropertyFlags pFlags = lyrics->propertyFlags(Pid::PLACEMENT); Segment* nextSegment = segment; if (back) { // search prev chord while ((nextSegment = nextSegment->prev1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } } else { // search next chord while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } } if (nextSegment == 0) return; changeState(ViewState::NORMAL); // look for the lyrics we are moving from; may be the current lyrics or a previous one // if we are skipping several chords with spaces Lyrics* fromLyrics = 0; if (!back) { while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (cr) { fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; } segment = segment->prev1(SegmentType::ChordRest); } } ChordRest* cr = toChordRest(nextSegment->element(track)); if (!cr) { qDebug("no next lyrics list: %s", nextSegment->element(track)->name()); return; } Lyrics* _toLyrics = cr->lyrics(verse, placement); bool newLyrics = false; if (!_toLyrics) { _toLyrics = new Lyrics(_score); _toLyrics->setTrack(track); ChordRest* cr = toChordRest(nextSegment->element(track)); _toLyrics->setParent(cr); _toLyrics->setNo(verse); _toLyrics->setPlacement(placement); _toLyrics->setPropertyFlags(Pid::PLACEMENT, pFlags); _toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE); newLyrics = true; } _score->startCmd(); if (fromLyrics && !moveOnly) { switch (_toLyrics->syllabic()) { // as we arrived at toLyrics by a [Space], it can be the beginning // of a multi-syllable, but cannot have syllabic dashes before case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::BEGIN: break; case Lyrics::Syllabic::END: _toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); break; case Lyrics::Syllabic::MIDDLE: _toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); break; } // as we moved away from fromLyrics by a [Space], it can be // the end of a multi-syllable, but cannot have syllabic dashes after switch (fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; case Lyrics::Syllabic::BEGIN: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); break; case Lyrics::Syllabic::MIDDLE: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } // for the same reason, it cannot have a melisma fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, 0); } if (newLyrics) _score->undoAddElement(_toLyrics); _score->endCmd(); _score->select(_toLyrics, SelectType::SINGLE, 0); startEdit(_toLyrics, Grip::NO_GRIP); adjustCanvasPosition(_toLyrics, false); TextCursor* cursor = toLyrics(editData.element)->cursor(editData); if (end) { cursor->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); cursor->movePosition(QTextCursor::End, QTextCursor::KeepAnchor); } else { cursor->movePosition(QTextCursor::End, QTextCursor::MoveAnchor); cursor->movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); } _score->setLayoutAll(); }
QPointF Pedal::linePos(Grip grip, System** sys) const { qreal x = 0.0; qreal nhw = score()->noteHeadWidth(); System* s = nullptr; if (grip == Grip::START) { ChordRest* c = toChordRest(startElement()); if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); if (beginHookType() == HookType::HOOK_45) x += nhw * .5; } } else { Element* e = endElement(); ChordRest* c = toChordRest(endElement()); if (!e || e == startElement() || (endHookType() == HookType::HOOK_90)) { // pedal marking on single note or ends with non-angled hook: // extend to next note or end of measure Segment* seg = nullptr; if (!e) seg = startSegment(); else seg = c->segment(); if (seg) { seg = seg->next(); for ( ; seg; seg = seg->next()) { if (seg->segmentType() == SegmentType::ChordRest) { // look for a chord/rest in any voice on this staff bool crFound = false; int track = staffIdx() * VOICES; for (int i = 0; i < VOICES; ++i) { if (seg->element(track + i)) { crFound = true; break; } } if (crFound) break; } else if (seg->segmentType() == SegmentType::EndBarLine) { break; } } } if (seg) { s = seg->system(); x = seg->pos().x() + seg->measure()->pos().x() - nhw * 2; } } else if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); } if (!s) { int t = tick2(); Measure* m = score()->tick2measure(t); s = m->system(); x = m->tick2pos(t); } if (endHookType() == HookType::HOOK_45) x += nhw * .5; else x += nhw; } *sys = s; return QPointF(x, 0); }
ChordRest* Fermata::chordRest() const { if (parent() && parent()->isChordRest()) return toChordRest(parent()); return 0; }