// // File: VLLilypondWriter.h // // Author(s): // // (MN) Matthias Neeracher // // Copyright © 2007-2018 Matthias Neeracher // #include "VLLilypondWriter.h" #include "VLPitchName.h" void VLLilypondWriter::Visit(VLSong & song) { fSong = &song; fChords.clear(); fMelody.clear(); fLyrics.clear(); fLyrics.resize(song.CountStanzas()); fL = fLyrics; fInPickup = true; fIndent.clear(); fSeenEnding = 0; fNumEndings = 0; fLastProp = 0; fPrevBreak = 0; fAutomaticLayout = true; for (int i=0; i 0; fInPickup = fInPickup && !m && meas.NoChords(); if (fInPickup) ++fPrevBreak; fInPickup = fInPickup && meas.CanSkipRests(); // // Generate chords // fAccum.clear(); VisitChords(meas); fAccum += measNo; fChords+= fAccum + '\n'; fAccum.clear(); // // Generate key/time if changed // if (!fLastProp || fLastProp->fTime != p.fTime) { char time[16]; sprintf(time, "\\time %d/%d\n", p.fTime.fNum, p.fTime.fDenom); fAccum += fIndent+time; } if (!fLastProp || fLastProp->fKey != p.fKey || fLastProp->fMode != p.fMode) { const int kMajorOffset = 6; const int kMinorOffset = 9; static const char * sKeyNames[] = { "ges", "des", "as", "es", "bes", "f", "c", "g", "d", "a", "e", "b", "fis", "cis", "gis" }; char key[16]; if (p.fMode < 0) sprintf(key, "\\key %s \\minor\n", sKeyNames[p.fKey+kMinorOffset]); else sprintf(key, "\\key %s \\major\n", sKeyNames[p.fKey+kMajorOffset]); fAccum += fIndent+key; } fLastProp = &p; // // Generate structure elements // int times; size_t volta; bool repeat; bool hasBarLine = false; if (meas.fBreak & VLMeasure::kNewPage) { fAccum += fIndent+"\\pageBreak\n"; hasBarLine = true; fPrevBreak = m; } else if ((meas.fBreak & VLMeasure::kNewSystem) || (fAutomaticLayout && m == fPrevBreak+4) ) { fAccum += fIndent+"\\break\n"; hasBarLine = true; fPrevBreak = m; } if (fSong->DoesEndRepeat(m)) { fAccum += "}\n"; fIndent = ""; hasBarLine = true; } if (fSong->DoesBeginEnding(m, &repeat, &volta)) { fAccum += fSeenEnding ? "}{\n" : "} \\alternative {{\n"; fAccum += " \\set Score.repeatCommands = #'((volta \""; const char * comma = ""; for (int r=0; r<8; ++r) if (volta & (1<DoesEndEnding(m, &hasBarLine)) { fAccum += "}}\n"; fIndent = ""; } if (fSong->DoesBeginRepeat(m, ×)) { char volta[8]; sprintf(volta, "%d", times); fAccum = fAccum + "\\repeat volta "+volta+" {\n"; fIndent = " "; fSeenEnding = 0; fNumEndings = 0; hasBarLine = true; } fAccum += fIndent; if (fSong->fCoda == m) { if (!hasBarLine) fAccum += "\\bar \"|.\" "; fAccum += "\\break \\mark \\markup { \\musicglyph #\"scripts.coda\" }\n" + fIndent; } fMelody += fAccum; // // Generate melody & lyrics // fAccum.clear(); for (size_t stanza=0; stanzafGoToCoda == m+1) fAccum += "\n" + fIndent + "\\mark \\markup { \\musicglyph #\"scripts.coda\" } |"; else fAccum += " |"; fMelody += fAccum + measNo + '\n'; // // Accumulate lyrics // const char * nuline = m%4 ? "" : "\n"; for (size_t stanza=0; stanza0; --ticks) nm += '\''; for (int commas = -1-octave; commas>0; --commas) nm += ','; fInPickup = false; } else if (fInPickup && n.fDuration.IsPowerOfTwo()) { nm = "s"; } const char * space = fAccum.size() ? " " : ""; const char * tie; switch (n.fTied & (VLNote::kTiedWithNext|VLNote::kSlurWithNext|VLNote::kStartSlur|VLNote::kEndSlur)) { case VLNote::kTiedWithNext|VLNote::kSlurWithNext|VLNote::kStartSlur: tie = "("; break; case VLNote::kTiedWithNext|VLNote::kStartSlur: tie = "~("; break; case VLNote::kTiedWithNext: tie = "~"; break; case VLNote::kEndSlur: tie = ")"; break; case VLNote::kTiedWithNext|VLNote::kSlurWithNext: default: tie = ""; break; } char duration[32]; if ((n.fTied & VLNote::kTiedWithPrev) && n.fVisual == fPrevNote.fVisual+1 && n.fPitch == fPrevNote.fPitch ) { strcpy(duration, "."); } else if (n.fVisual & VLNote::kTupletMask) { sprintf(duration, "%s\\times %d/%d { %s%d%s }", space, VLNote::TupletDenom(n.fVisual), VLNote::TupletNum(n.fVisual), nm.c_str(), kValue[n.fVisual & VLNote::kNoteHeadMask], tie); } else { sprintf(duration, "%s%s%d%s", space, nm.c_str(), kValue[n.fVisual & VLNote::kNoteHeadMask], tie); } fAccum += duration; fPrevNote = n; if (n.fPitch != VLNote::kNoPitch && !(n.fTied & VLNote::kTiedWithPrev)) { for (size_t i=0; i VLChord::kDim7th; --step) if (unaltered & (1 << step)) { std::string sn = kLilypondStepNames[step]; if (ext.size() && !isalpha(ext[ext.size()-1]) && sn.size()) ext += '.'; ext += sn; break; } } for (int step = VLChord::kMin2nd; steps; ++step) if (steps & (1 << step)) { std::string sn = kLilypondStepNames[step]; if (ext.size() && !isalpha(ext[ext.size()-1]) && sn.size()) ext += '.'; ext += sn; steps &= ~(1 << step); } if (ext.size()) name += ':' + ext; // // Root // if (c.fRootPitch != VLNote::kNoPitch) name += "/+" + VLPitchName(c.fRootPitch, c.fRootAccidental, 0, kVLLilypondNames); done: if (fAccum.size()) fAccum += ' '; fAccum += name; }