From 144a19d229a720b724ce219831954659ee3d7410 Mon Sep 17 00:00:00 2001 From: Matthias Neeracher Date: Sun, 28 Aug 2011 17:21:12 +0200 Subject: [PATCH] Properly represent double accidentals in lilypond output --- Sources/VLLilypondWriter.cpp | 31 ++++++--------------- Sources/VLPitchName.cpp | 54 ++++++++++++++++++++++-------------- Sources/VLPitchName.h | 9 ++++-- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Sources/VLLilypondWriter.cpp b/Sources/VLLilypondWriter.cpp index a08ca9c..6fc1417 100644 --- a/Sources/VLLilypondWriter.cpp +++ b/Sources/VLLilypondWriter.cpp @@ -9,6 +9,7 @@ // #include "VLLilypondWriter.h" +#include "VLPitchName.h" void VLLilypondWriter::Visit(VLSong & song) { @@ -182,24 +183,10 @@ void VLLilypondWriter::VisitMeasure(size_t m, VLProperties & p, VLMeasure & meas fLyrics[stanza] += fL[stanza] + nuline; } -static const char kScale[] = "c d ef g a b"; static const char kValue[] = { 1, 2, 4, 8, 16, 32 }; -static std::string LilypondPitchName(int8_t pitch, bool useSharps, bool restIsSkip) -{ - if (pitch == VLNote::kNoPitch) - return restIsSkip ? "s" : "r"; - pitch %= 12; - if (kScale[pitch] != ' ') - return kScale[pitch] + std::string(); - else if (useSharps) - return kScale[pitch-1] + std::string("is"); - else - return kScale[pitch+1] + std::string("es"); -} - static std::string EscapeSyllable(std::string syll) { bool seenAlpha = false; @@ -256,13 +243,12 @@ static bool PreferSharps(bool globalSharps, int noteAccidentals) void VLLilypondWriter::VisitNote(VLLyricsNote & n) { - std::string nm = - LilypondPitchName(n.fPitch, PreferSharps(fUseSharps, n.fVisual), false); + int octave; + std::string nm = VLPitchName(n.fPitch, n.fVisual, &octave, kVLLilypondNames); if (n.fPitch != VLNote::kNoPitch) { - int ref = VLNote::kMiddleC-VLNote::kOctave; - for (int ticks = (n.fPitch-ref)/VLNote::kOctave; ticks>0; --ticks) + for (int ticks = octave+1; ticks>0; --ticks) nm += '\''; - for (int commas = (ref-n.fPitch)/VLNote::kOctave; commas>0; --commas) + for (int commas = -1-octave; commas>0; --commas) nm += ','; fInPickup = false; } else if (fInPickup) { @@ -303,8 +289,9 @@ static const char * kLilypondStepNames[] = { void VLLilypondWriter::VisitChord(VLChord & c) { - std::string name = - LilypondPitchName(c.fPitch, PreferSharps(fUseSharps, c.fVisual), true); + std::string name = VLPitchName(c.fPitch, c.fVisual, 0, kVLLilypondNames); + if (name == "r") + name = "s"; char duration[16]; if (c.fDuration.fNum == 1 && !(c.fDuration.fDenom & (c.fDuration.fDenom-1))) // Power of two sprintf(duration, "%d", c.fDuration.fDenom); @@ -396,7 +383,7 @@ void VLLilypondWriter::VisitChord(VLChord & c) // Root // if (c.fRootPitch != VLNote::kNoPitch) - name += "/+" + LilypondPitchName(c.fRootPitch, fUseSharps, false); + name += "/+" + VLPitchName(c.fRootPitch, c.fRootAccidental, 0, kVLLilypondNames); done: if (fAccum.size()) diff --git a/Sources/VLPitchName.cpp b/Sources/VLPitchName.cpp index 1c06089..9885a1d 100644 --- a/Sources/VLPitchName.cpp +++ b/Sources/VLPitchName.cpp @@ -13,25 +13,32 @@ #define SHARP "\xE2\x99\xAF" #define FLAT "\xE2\x99\xAD" +#define SCALE "C D EF G A B" const char * kVLSharpStr = SHARP; const char * kVLFlatStr = FLAT; const char * kVL2SharpStr = "\xF0\x9D\x84\xAA"; const char * kVL2FlatStr = "\xF0\x9D\x84\xAB"; const char * kVLNaturalStr = "\xE2\x99\xAE"; - -static const char kScale[] = "C D EF G A B"; -static const char * kFancyAccidental[] = +const char * kVLFancyNames[] = { - kVL2SharpStr, kVLSharpStr, "", kVLFlatStr, kVL2FlatStr + SCALE, "R", kVLNaturalStr, kVL2SharpStr, kVLSharpStr, "", kVLFlatStr, kVL2FlatStr }; -const int8_t kAccidentalBase = 2; - -std::string VLPitchName(int8_t pitch, uint16_t accidental) +const char * kVLLilypondNames[] = { + "c d ef g a b", "r", "", "isis", "is", "", "es", "eses" +}; + +const int8_t kAccidentalBase = 5; + +std::string VLPitchName(int8_t pitch, uint16_t accidental, int * octave, const char *names[]) +{ + const char * kScale = names[0]; + const char * kRest = names[1]; if (pitch == VLNote::kNoPitch) - return "r"; + return kRest; int8_t adjust; + int8_t semi; accidental &= VLNote::kAccidentalsMask; switch (accidental) { case VLNote::kWant2Flat: @@ -50,24 +57,28 @@ std::string VLPitchName(int8_t pitch, uint16_t accidental) adjust = 0; break; } - pitch += adjust; - pitch %= 12; + pitch += adjust; + semi = pitch % 12; // // Will either succeed immediately, or after one adjustment // - if (kScale[pitch] == ' ') + if (kScale[semi] == ' ') if (adjust < 0 || (accidental & VLNote::kPreferFlats) == VLNote::kPreferFlats) { ++adjust; - pitch = (pitch+1)%12; + ++pitch; + semi = (semi+1)%12; } else { --adjust; - pitch = (pitch+11)%12; + --pitch; + semi = (semi+11)%12; } - std::string name = std::string(1, kScale[pitch]); + std::string name = std::string(1, kScale[semi]); + if (octave) + *octave = (pitch / VLNote::kOctave)-5; if (adjust) - return name+kFancyAccidental[adjust+kAccidentalBase]; + return name+names[adjust+kAccidentalBase]; else if ((accidental & VLNote::kWantNatural) == VLNote::kWantNatural) - return name+kVLNaturalStr; + return name+names[2]; else return name; } @@ -103,8 +114,8 @@ int8_t VLParsePitch(std::string & str, size_t at, uint16_t * accidental) // // Determine key // - if (const char * key = strchr(kScale, std::toupper(str[at]))) { - pitch = key-kScale+VLNote::kMiddleC; + if (const char * key = strchr(SCALE, std::toupper(str[at]))) { + pitch = key-SCALE+VLNote::kMiddleC; } else if (str[at] == 'r' || str[at] == 's') { str.erase(at, 1); // Rest return VLNote::kNoPitch; @@ -135,13 +146,14 @@ static const char * kStepNames[] = { void VLChordName(int8_t pitch, uint16_t accidental, uint32_t steps, int8_t rootPitch, uint16_t rootAccidental, - std::string & baseName, std::string & extName, std::string & rootName) + std::string & baseName, std::string & extName, std::string & rootName, + const char * names[]) { - baseName = VLPitchName(pitch, accidental); + baseName = VLPitchName(pitch, accidental, 0, names); if (rootPitch == VLNote::kNoPitch) rootName.clear(); else - rootName = VLPitchName(rootPitch, rootAccidental); + rootName = VLPitchName(rootPitch, rootAccidental, 0, names); // // m / dim // diff --git a/Sources/VLPitchName.h b/Sources/VLPitchName.h index 565534a..5a2627e 100644 --- a/Sources/VLPitchName.h +++ b/Sources/VLPitchName.h @@ -18,11 +18,13 @@ extern const char * kVLFlatStr; extern const char * kVL2SharpStr; extern const char * kVL2FlatStr; extern const char * kVLNaturalStr; - +extern const char * kVLFancyNames[]; +extern const char * kVLLilypondNames[]; // // UTF-8 representation of pitch // -std::string VLPitchName(int8_t pitch, uint16_t accidental); +std::string VLPitchName(int8_t pitch, uint16_t accidental, int * octave = 0, + const char * names[] = kVLFancyNames); // // Parse pitch, erase from string @@ -35,7 +37,8 @@ int8_t VLParsePitch(std::string & str, size_t at, uint16_t * accidental); // void VLChordName(int8_t pitch, uint16_t accidental, uint32_t steps, int8_t rootPitch, uint16_t rootAccidental, - std::string & baseName, std::string & extName, std::string & rootName); + std::string & baseName, std::string & extName, std::string & rootName, + const char * names[] = kVLFancyNames); // // Parse chord name, erase from string