📄 lilypondexporter.cpp
字号:
tmpStr.replace(QRegExp("\\^"), "\\^"); tmpStr.replace(QRegExp("%"), "\\%"); tmpStr.replace(QRegExp("<"), "\\<"); tmpStr.replace(QRegExp(">"), "\\>"); tmpStr.replace(QRegExp("\\["), ""); tmpStr.replace(QRegExp("\\]"), ""); tmpStr.replace(QRegExp("\\{"), ""); tmpStr.replace(QRegExp("\\}"), ""); // // LilyPond uses utf8 encoding. // return tmpStr.utf8().data();}boolLilypondExporter::write(){ QString tmpName = strtoqstr(m_fileName); // dmm - modified to act upon the filename itself, rather than the whole // path; fixes bug #855349 // split name into parts: QFileInfo nfo(tmpName); QString dirName = nfo.dirPath(); QString baseName = nfo.fileName(); // sed Lilypond-choking chars out of the filename proper bool illegalFilename = (baseName.contains(' ') || baseName.contains("\\")); baseName.replace(QRegExp(" "), ""); baseName.replace(QRegExp("\\\\"), ""); baseName.replace(QRegExp("'"), ""); baseName.replace(QRegExp("\""), ""); // cat back together tmpName = dirName + '/' + baseName; if (illegalFilename) { CurrentProgressDialog::freeze(); int reply = KMessageBox::warningContinueCancel( 0, i18n("Lilypond does not allow spaces or backslashes in filenames.\n\n" "Would you like to use\n\n %1\n\n instead?").arg(baseName)); if (reply != KMessageBox::Continue) return false; } std::ofstream str(qstrtostr(tmpName).c_str(), std::ios::out); if (!str) { std::cerr << "LilypondExporter::write() - can't write file " << tmpName << std::endl; return false; } str << "% This LilyPond file was generated by Rosegarden " << protectIllegalChars(VERSION) << std::endl; switch (m_languageLevel) { case LILYPOND_VERSION_2_6: str << "\\version \"2.6.0\"" << std::endl; break; case LILYPOND_VERSION_2_8: str << "\\version \"2.8.0\"" << std::endl; break; case LILYPOND_VERSION_2_10: str << "\\version \"2.10.0\"" << std::endl; break; case LILYPOND_VERSION_2_12: str << "\\version \"2.12.0\"" << std::endl; break; default: // force the default version if there was an error std::cerr << "ERROR: Unknown language level " << m_languageLevel << ", using \\version \"2.6.0\" instead" << std::endl; str << "\\version \"2.6.0\"" << std::endl; m_languageLevel = LILYPOND_VERSION_2_6; } // enable "point and click" debugging via pdf to make finding the // unfortunately inevitable errors easier if (m_exportPointAndClick) { str << "% point and click debugging is enabled" << std::endl; } else { str << "% point and click debugging is disabled" << std::endl; str << "#(ly:set-option 'point-and-click #f)" << std::endl; } // Lilypond \header block // set indention level to make future changes to horizontal layout less // tedious, ++col to indent a new level, --col to de-indent int col = 0; // grab user headers from metadata Configuration metadata = m_composition->getMetadata(); std::vector<std::string> propertyNames = metadata.getPropertyNames(); // open \header section if there's metadata to grab, and if the user // wishes it if (!propertyNames.empty()) { str << "\\header {" << std::endl; col++; // indent+ bool userTagline = false; for (unsigned int index = 0; index < propertyNames.size(); ++index) { std::string property = propertyNames [index]; if (property == headerDedication || property == headerTitle || property == headerSubtitle || property == headerSubsubtitle || property == headerPoet || property == headerComposer || property == headerMeter || property == headerOpus || property == headerArranger || property == headerInstrument || property == headerPiece || property == headerCopyright || property == headerTagline) { std::string header = protectIllegalChars(metadata.get<String>(property)); if (header != "") { str << indent(col) << property << " = \"" << header << "\"" << std::endl; // let users override defaults, but allow for providing // defaults if they don't: if (property == headerTagline) userTagline = true; } } } // default tagline if (!userTagline) { str << indent(col) << "tagline = \"" << "Created using Rosegarden " << protectIllegalChars(VERSION) << " and LilyPond" << "\"" << std::endl; } // close \header str << indent(--col) << "}" << std::endl; } // Lilypond \paper block (optional) if (m_raggedBottom) { str << indent(col) << "\\paper {" << std::endl; str << indent(++col) << "ragged-bottom=##t" << std::endl; str << indent(--col) << "}" << std::endl; } // Lilypond music data! Mapping: // Lilypond Voice = Rosegarden Segment // Lilypond Staff = Rosegarden Track // (not the cleanest output but maybe the most reliable) // paper/font sizes int font; switch (m_fontSize) { case 0 : font = 11; break; case 1 : font = 13; break; case 2 : font = 16; break; case 3 : font = 19; break; case 4 : font = 20; break; case 5 : font = 23; break; case 6 : font = 26; break; default : font = 20; // if config problem } str << indent(col) << "#(set-global-staff-size " << font << ")" << std::endl; // write user-specified paper type as default paper size std::string paper = ""; switch (m_paperSize) { case PAPER_A3 : paper += "a3"; break; case PAPER_A4 : paper += "a4"; break; case PAPER_A5 : paper += "a5"; break; case PAPER_A6 : paper += "a6"; break; case PAPER_LEGAL : paper += "legal"; break; case PAPER_LETTER : paper += "letter"; break; case PAPER_TABLOID : paper += "tabloid"; break; case PAPER_NONE : paper = ""; break; // "do not specify" } if (paper != "") { str << indent(col) << "#(set-default-paper-size \"" << paper << "\"" << (m_paperLandscape ? " 'landscape" : "") << ")" << std::endl; } // Find out the printed length of the composition Composition::iterator i = m_composition->begin(); if ((*i) == NULL) { str << indent(col) << "\\score {" << std::endl; str << indent(++col) << "% no segments found" << std::endl; // bind staffs with or without staff group bracket str << indent(col) // indent << "<<" << " s4 " << ">>" << std::endl; str << indent(col) << "\\layout { }" << std::endl; str << indent(--col) << "}" << std::endl; return true; } timeT compositionStartTime = (*i)->getStartTime(); timeT compositionEndTime = (*i)->getEndMarkerTime(); for (; i != m_composition->end(); ++i) { if (compositionStartTime > (*i)->getStartTime() && (*i)->getTrack() >= 0) { compositionStartTime = (*i)->getStartTime(); } if (compositionEndTime < (*i)->getEndMarkerTime()) { compositionEndTime = (*i)->getEndMarkerTime(); } } // define global context which is common for all staffs str << indent(col++) << "global = { " << std::endl; TimeSignature timeSignature = m_composition-> getTimeSignatureAt(m_composition->getStartMarker()); if (m_composition->getBarStart(m_composition->getBarNumber(compositionStartTime)) < compositionStartTime) { str << indent(col) << "\\partial "; // Arbitrary partial durations are handled by the following way: // split the partial duration to 64th notes: instead of "4" write "64*16". (hjj) Note partialNote = Note::getNearestNote(1, MAX_DOTS); int partialDuration = m_composition->getBarStart(m_composition->getBarNumber(compositionStartTime) + 1) - compositionStartTime; writeDuration(1, str); str << "*" << ((int)(partialDuration / partialNote.getDuration())) << std::endl; } int leftBar = 0; int rightBar = leftBar; do { bool isNew = false; m_composition->getTimeSignatureInBar(rightBar + 1, isNew); if (isNew || (m_composition->getBarStart(rightBar + 1) >= compositionEndTime)) { // - set initial time signature; further time signature changes // are defined within the segments, because they may be hidden str << indent(col) << (leftBar == 0 ? "" : "% ") << "\\time " << timeSignature.getNumerator() << "/" << timeSignature.getDenominator() << std::endl; // - place skips upto the end of the composition; // this justifies the printed staffs str << indent(col); timeT leftTime = m_composition->getBarStart(leftBar); timeT rightTime = m_composition->getBarStart(rightBar + 1); if (leftTime < compositionStartTime) { leftTime = compositionStartTime; } writeSkip(timeSignature, leftTime, rightTime - leftTime, false, str); str << " %% " << (leftBar + 1) << "-" << (rightBar + 1) << std::endl; timeSignature = m_composition->getTimeSignatureInBar(rightBar + 1, isNew); leftBar = rightBar + 1; } } while (m_composition->getBarStart(++rightBar) < compositionEndTime); str << indent(--col) << "}" << std::endl; // time signatures changes are in segments, reset initial value timeSignature = m_composition-> getTimeSignatureAt(m_composition->getStartMarker()); // All the tempo changes are included in "globalTempo" context. // This context contains only skip notes between the tempo changes. // First tempo marking should still be include in \midi{ } block. // If tempo marks are printed in future, they should probably be // included in this context and the note duration in the tempo // mark should be according to the time signature. (hjj) int tempoCount = m_composition->getTempoChangeCount(); if (tempoCount > 0) { timeT prevTempoChangeTime = m_composition->getStartMarker(); int tempo = int(Composition::getTempoQpm(m_composition->getTempoAtTime(prevTempoChangeTime))); bool tempoMarksInvisible = false; str << indent(col++) << "globalTempo = {" << std::endl; if (m_exportTempoMarks == EXPORT_NONE_TEMPO_MARKS && tempoMarksInvisible == false) { str << indent(col) << "\\override Score.MetronomeMark #'transparent = ##t" << std::endl; tempoMarksInvisible = true; } str << indent(col) << "\\tempo 4 = " << tempo << " "; int prevTempo = tempo; for (int i = 0; i < tempoCount; ++i) { std::pair<timeT, long> tempoChange = m_composition->getTempoChange(i); timeT tempoChangeTime = tempoChange.first; tempo = int(Composition::getTempoQpm(tempoChange.second)); // First tempo change may be before the first segment. // Do not apply it before the first segment appears. if (tempoChangeTime < compositionStartTime) { tempoChangeTime = compositionStartTime; } else if (tempoChangeTime >= compositionEndTime) { tempoChangeTime = compositionEndTime; } if (prevTempoChangeTime < compositionStartTime) { prevTempoChangeTime = compositionStartTime; } else if (prevTempoChangeTime >= compositionEndTime) { prevTempoChangeTime = compositionEndTime; } writeSkip(m_composition->getTimeSignatureAt(tempoChangeTime), tempoChangeTime, tempoChangeTime - prevTempoChangeTime, false, str); // add new \tempo only if tempo was changed if (tempo != prevTempo) { if (m_exportTempoMarks == EXPORT_FIRST_TEMPO_MARK && tempoMarksInvisible == false) { str << std::endl << indent(col) << "\\override Score.MetronomeMark #'transparent = ##t"; tempoMarksInvisible = true; } str << std::endl << indent(col) << "\\tempo 4 = " << tempo << " "; } prevTempo = tempo; prevTempoChangeTime = tempoChangeTime; if (prevTempoChangeTime == compositionEndTime)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -