void LyricEditDialog::unparse() { // This and SetLyricsCommand::execute() are opposites that will // need to be kept in sync with any changes in one another. (They // should really both be in a common lyric management class.) countVerses(); Composition *comp = m_segment->getComposition(); bool firstNote = true; timeT lastTime = m_segment->getStartTime(); int lastBarNo = comp->getBarNumber(lastTime); std::map<int, bool> haveLyric; QString fragment = QString("[%1] ").arg(lastBarNo + 1); m_skeleton = fragment; m_texts.clear(); for (int v = 0; v < m_verseCount; ++v) { m_texts.push_back(fragment); haveLyric[v] = false; } for (Segment::iterator i = m_segment->begin(); m_segment->isBeforeEndMarker(i); ++i) { bool isNote = (*i)->isa(Note::EventType); bool isLyric = false; if (!isNote) { if ((*i)->isa(Text::EventType)) { std::string textType; if ((*i)->get<String>(Text::TextTypePropertyName, textType) && textType == Text::Lyric) { isLyric = true; } } } else { if ((*i)->has(BaseProperties::TIED_BACKWARD) && (*i)->get<Bool>(BaseProperties::TIED_BACKWARD)) { continue; } } if (!isNote && !isLyric) continue; timeT myTime = (*i)->getNotationAbsoluteTime(); int myBarNo = comp->getBarNumber(myTime); if (myBarNo > lastBarNo) { fragment = ""; while (myBarNo > lastBarNo) { fragment += " /"; ++lastBarNo; } fragment += QString("\n[%1] ").arg(myBarNo + 1); m_skeleton += fragment; for (int v = 0; v < m_verseCount; ++v) m_texts[v] += fragment; } if (isNote) { if ((myTime > lastTime) || firstNote) { m_skeleton += " ."; for (int v = 0; v < m_verseCount; ++v) { if (!haveLyric[v]) m_texts[v] += " ."; haveLyric[v] = false; } lastTime = myTime; firstNote = false; } } if (isLyric) { std::string ssyllable; (*i)->get<String>(Text::TextPropertyName, ssyllable); long verse = 0; (*i)->get<Int>(Text::LyricVersePropertyName, verse); QString syllable(strtoqstr(ssyllable)); syllable.replace(QRegExp("\\s+"), "~"); m_texts[verse] += " " + syllable; haveLyric[verse] = true; } } if (!m_texts.empty()) { m_textEdit->setPlainText(m_texts[0]); } else { m_texts.push_back(m_skeleton); } }
void SetLyricsCommand::execute() { // This and LyricEditDialog::unparse() are opposites that will // need to be kept in sync with any changes to one another. (They // should really both be in a common lyric management class.) // first remove old lyric events Segment::iterator i = m_segment->begin(); while (i != m_segment->end()) { Segment::iterator j = i; ++j; if ((*i)->isa(Text::EventType)) { std::string textType; if ((*i)->get<String>(Text::TextTypePropertyName, textType) && textType == Text::Lyric) { long verse = 0; (*i)->get<Int>(Text::LyricVersePropertyName, verse); if (verse == m_verse) { m_oldLyricEvents.push_back(new Event(**i)); m_segment->erase(i); } } } i = j; } // now parse the new string QStringList barStrings = m_newLyricData.split("/", QString::KeepEmptyParts); // empties ok Composition *comp = m_segment->getComposition(); int barNo = comp->getBarNumber(m_segment->getStartTime()); QStringList::Iterator bsi = barStrings.begin(); while ( bsi != barStrings.end() ) { NOTATION_DEBUG << "Parsing lyrics for bar number " << barNo << ": \"" << *bsi << "\"" << endl; std::pair<timeT, timeT> barRange = comp->getBarRange(barNo++); QString syllables = *bsi; syllables.replace(QRegExp("\\[\\d+\\] "), " "); syllables.replace(QRegExp("\n"), " "); QStringList syllableList = syllables.split(" ", QString::SkipEmptyParts); // no empties i = m_segment->findTime(barRange.first); timeT laterThan = barRange.first - 1; ++bsi; // update here in order to check whether we are in the last bar string bool isLastBSI = (bsi == barStrings.end()); for (QStringList::Iterator ssi = syllableList.begin(); ssi != syllableList.end(); ++ssi) { // As a rule, syllables belong to a certain bar. However, from the // last barString list syllables may flow to the following bars. // As a result, one may copy&paste the full syllable list of a verse. while (m_segment->isBeforeEndMarker(i) && (isLastBSI || (*i)->getAbsoluteTime() < barRange.second) && (!(*i)->isa(Note::EventType) || (*i)->getNotationAbsoluteTime() <= laterThan || ((*i)->has(TIED_BACKWARD) && (*i)->get <Bool>(TIED_BACKWARD)))) ++i; timeT time = m_segment->getEndMarkerTime(); timeT notationTime = time; if (m_segment->isBeforeEndMarker(i)) { time = (*i)->getAbsoluteTime(); notationTime = (*i)->getNotationAbsoluteTime(); } QString syllable = *ssi; syllable.replace(QRegExp("~"), " "); syllable = syllable.simplified(); if (syllable == "") continue; laterThan = notationTime + 1; if (syllable == ".") continue; NOTATION_DEBUG << "Syllable \"" << syllable << "\" at time " << time << endl; Text text(qstrtostr(syllable), Text::Lyric); Event *event = text.getAsEvent(time); event->set<Int>(Text::LyricVersePropertyName, m_verse); m_segment->insert(event); } } }