📄 lilypondexporter.cpp
字号:
} if (isLyric) { long verse; (*j)->get<Int>(Text::LyricVersePropertyName, verse); if (verse == currentVerse) { std::string ssyllable; (*j)->get<String>(Text::TextPropertyName, ssyllable); text += " "; QString syllable(strtoqstr(ssyllable)); syllable.replace(QRegExp("\\s+"), ""); text += "\"" + syllable + "\""; haveLyric = true; } else if (verse > lastVerse) { lastVerse = verse; } } } text.replace( QRegExp(" _+([^ ])") , " \\1" ); text.replace( "\"_\"" , " " ); // Do not create empty context for lyrics. // Does this save some vertical space, as was written // in earlier comment? QRegExp rx( "\"" ); if ( rx.search( text ) != -1 ) { str << indent(col) << "\\lyricsto \"" << voiceNumber.str() << "\"" << " \\new Lyrics \\lyricmode {" << std::endl; if (m_lyricsHAlignment == RIGHT_ALIGN) { str << indent(++col) << "\\override LyricText #'self-alignment-X = #RIGHT" << std::endl; } else if (m_lyricsHAlignment == CENTER_ALIGN) { str << indent(++col) << "\\override LyricText #'self-alignment-X = #CENTER" << std::endl; } else { str << indent(++col) << "\\override LyricText #'self-alignment-X = #LEFT" << std::endl; } str << indent(col) << "\\set ignoreMelismata = ##t" << std::endl; str << indent(col) << text.utf8() << " " << std::endl; str << indent(col) << "\\unset ignoreMelismata" << std::endl; str << indent(--col) << "} % Lyrics " << (currentVerse+1) << std::endl; // close the Lyrics context } } } } } } // close the last track (Staff context) if (voiceCounter > 0) { str << indent(--col) << ">> % Staff (final)"; // indent- } else { str << indent(--col) << "% (All staffs were muted.)" << std::endl; } // close \notes section str << std::endl << indent(--col) << ">> % notes" << std::endl << std::endl; // indent- // write \layout block str << indent(col) << "\\layout { }" << std::endl; // write initial tempo in Midi block, if user wishes (added per user request... // makes debugging the .ly file easier because fewer "noisy" errors are // produced during the process of rendering MIDI...) if (m_exportMidi) { int tempo = int(Composition::getTempoQpm(m_composition->getTempoAtTime(m_composition->getStartMarker()))); // Incomplete? Can I get away without converting tempo relative to the time // signature for this purpose? we'll see... str << indent(col++) << "\\midi {" << std::endl; str << indent(col) << "\\tempo 4 = " << tempo << std::endl; str << indent(--col) << "} " << std::endl; } // close \score section and close out the file str << "} % score" << std::endl; str.close(); return true;}timeT LilypondExporter::calculateDuration(Segment *s, const Segment::iterator &i, timeT barEnd, timeT &soundingDuration, const std::pair<int, int> &tupletRatio, bool &overlong){ timeT duration = (*i)->getNotationDuration(); timeT absTime = (*i)->getNotationAbsoluteTime(); RG_DEBUG << "LilypondExporter::calculateDuration: first duration, absTime: " << duration << ", " << absTime << endl; timeT durationCorrection = 0; if ((*i)->isa(Note::EventType) || (*i)->isa(Note::EventRestType)) { try { // tuplet compensation, etc Note::Type type = (*i)->get<Int>(NOTE_TYPE); int dots = (*i)->get<Int>(NOTE_DOTS); durationCorrection = Note(type, dots).getDuration() - duration; } catch (Exception e) { // no properties } } duration += durationCorrection; RG_DEBUG << "LilypondExporter::calculateDuration: now duration is " << duration << " after correction of " << durationCorrection << endl; soundingDuration = duration * tupletRatio.first/ tupletRatio.second; timeT toNext = barEnd - absTime; if (soundingDuration > toNext) { soundingDuration = toNext; duration = soundingDuration * tupletRatio.second/ tupletRatio.first; overlong = true; } RG_DEBUG << "LilypondExporter::calculateDuration: time to barEnd is " << toNext << endl; // Examine the following event, and truncate our duration // if we overlap it. Segment::iterator nextElt = s->end(); toNext = soundingDuration; if ((*i)->isa(Note::EventType)) { Chord chord(*s, i, m_composition->getNotationQuantizer()); Segment::iterator nextElt = chord.getFinalElement(); ++nextElt; if (s->isBeforeEndMarker(nextElt)) { // The quantizer sometimes sticks a rest at the same time // as this note -- don't use that one here, and mark it as // not to be exported -- it's just a heavy-handed way of // rendering counterpoint in RG if ((*nextElt)->isa(Note::EventRestType) && (*nextElt)->getNotationAbsoluteTime() == absTime) { (*nextElt)->set<Bool>(SKIP_PROPERTY, true); ++nextElt; } } } else { nextElt = i; ++nextElt; while (s->isBeforeEndMarker(nextElt)) { if ((*nextElt)->isa(Controller::EventType) || (*nextElt)->isa(ProgramChange::EventType) || (*nextElt)->isa(SystemExclusive::EventType) || (*nextElt)->isa(ChannelPressure::EventType) || (*nextElt)->isa(KeyPressure::EventType) || (*nextElt)->isa(PitchBend::EventType)) ++nextElt; else break; } } if (s->isBeforeEndMarker(nextElt)) { RG_DEBUG << "LilypondExporter::calculateDuration: inside conditional " << endl; toNext = (*nextElt)->getNotationAbsoluteTime() - absTime; // if the note was lengthened, assume it was lengthened to the left // when truncating to the beginning of the next note if (durationCorrection > 0) { toNext += durationCorrection; } if (soundingDuration > toNext) { soundingDuration = toNext; duration = soundingDuration * tupletRatio.second/ tupletRatio.first; } } RG_DEBUG << "LilypondExporter::calculateDuration: second toNext is " << toNext << endl; RG_DEBUG << "LilypondExporter::calculateDuration: final duration, soundingDuration: " << duration << ", " << soundingDuration << endl; return duration;}voidLilypondExporter::writeBar(Segment *s, int barNo, int barStart, int barEnd, int col, Rosegarden::Key &key, std::string &lilyText, std::string &prevStyle, eventendlist &eventsInProgress, std::ofstream &str, int &MultiMeasureRestCount, bool &nextBarIsAlt1, bool &nextBarIsAlt2, bool &nextBarIsDouble, bool &nextBarIsEnd, bool &nextBarIsDot){ int lastStem = 0; // 0 => unset, -1 => down, 1 => up Segment::iterator i = s->findTime(barStart); if (!s->isBeforeEndMarker(i)) return ; if (MultiMeasureRestCount == 0) { str << std::endl; if ((barNo + 1) % 5 == 0) { str << "%% " << barNo + 1 << std::endl << indent(col); } else { str << indent(col); } } bool isNew = false; TimeSignature timeSignature = m_composition->getTimeSignatureInBar(barNo, isNew); if (isNew) { if (timeSignature.isHidden()) { str << "\\once \\override Staff.TimeSignature #'break-visibility = #(vector #f #f #f) "; } str << "\\time " << timeSignature.getNumerator() << "/" << timeSignature.getDenominator() << std::endl << indent(col); } timeT absTime = (*i)->getNotationAbsoluteTime(); timeT writtenDuration = 0; std::pair<int,int> barDurationRatio(timeSignature.getNumerator(),timeSignature.getDenominator()); std::pair<int,int> durationRatioSum(0,1); static std::pair<int,int> durationRatio(0,1); if (absTime > barStart) { Note note(Note::getNearestNote(absTime - barStart, MAX_DOTS)); writtenDuration += note.getDuration(); durationRatio = writeSkip(timeSignature, 0, note.getDuration(), true, str); durationRatioSum = fractionSum(durationRatioSum,durationRatio); // str << qstrtostr(QString(" %{ %1/%2 %} ").arg(durationRatio.first).arg(durationRatio.second)); // DEBUG } timeT prevDuration = -1; eventstartlist eventsToStart; long groupId = -1; std::string groupType = ""; std::pair<int, int> tupletRatio(1, 1); bool overlong = false; bool newBeamedGroup = false; int notesInBeamedGroup = 0; while (s->isBeforeEndMarker(i)) { if ((*i)->getNotationAbsoluteTime() >= barEnd) break; // First test whether we're entering or leaving a group, // before we consider how to write the event itself (at least // for pre-2.0 Lilypond output) if ((*i)->isa(Note::EventType) || (*i)->isa(Note::EventRestType) || (*i)->isa(Clef::EventType) || (*i)->isa(Rosegarden::Key::EventType)) { long newGroupId = -1; if ((*i)->get <Int>(BEAMED_GROUP_ID, newGroupId)) { if (newGroupId != groupId) { // entering a new beamed group if (groupId != -1) { // and leaving an old one if (groupType == GROUP_TYPE_TUPLED || groupType == GROUP_TYPE_GRACE) { if (m_exportBeams && notesInBeamedGroup > 0) str << "] "; str << "} "; } else if (groupType == GROUP_TYPE_BEAMED) { if (m_exportBeams && notesInBeamedGroup > 0) str << "] "; } } groupId = newGroupId; groupType = ""; (void)(*i)->get <String>(BEAMED_GROUP_TYPE, groupType); if (groupType == GROUP_TYPE_TUPLED) { long numerator = 0; long denominator = 0; (*i)->get <Int>(BEAMED_GROUP_TUPLED_COUNT, numerator); (*i)->get <Int>(BEAMED_GROUP_UNTUPLED_COUNT, denominator); if (numerator == 0 || denominator == 0) { std::cerr << "WARNING: LilypondExporter::writeBar: " << "tupled event without tupled/untupled counts" << std::endl; groupId = -1; groupType = ""; } else { str << "\\times " << numerator << "/" << denominator << " { "; tupletRatio = std::pair<int, int>(numerator, denominator); // Require explicit beamed groups, // fixes bug #1683205. // HJJ: Why line below was originally present? // newBeamedGroup = true; notesInBeamedGroup = 0; } } else if (groupType == GROUP_TYPE_BEAMED) { newBeamedGroup = true; notesInBeamedGroup = 0; // there can currently be only on group type, reset tuplet ratio tupletRatio = std::pair<int, int>(1,1); } else if (groupType == GROUP_TYPE_GRACE) { str << "\\grace { "; // Require explicit beamed group, // fixes bug #1683205. // HJJ: Why line below was originally present? // newBeamedGroup = true; notesInBeamedGroup = 0; // there can currently be only on group type, reset tuplet ratio tupletRatio = std::pair<int, int>(1,1); } } } else { if (groupId != -1) { // leaving a beamed group if (groupType == GROUP_TYPE_TUPLED || groupType == GROUP_TYPE_GRACE) { if (m_exportBeams && notesInBeamedGroup > 0) str << "] "; str << "} "; tupletRatio = std::pair<int, int>(1, 1); } else if (groupType == GROUP_TYPE_BEAMED) { if (m_exportBeams && notesInBeamedGroup > 0) str << "] "; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -