mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Properly represent double accidentals in lilypond output
This commit is contained in:
parent
ed2a79a74e
commit
144a19d229
|
@ -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())
|
||||
|
|
|
@ -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:
|
||||
|
@ -51,23 +58,27 @@ std::string VLPitchName(int8_t pitch, uint16_t accidental)
|
|||
break;
|
||||
}
|
||||
pitch += adjust;
|
||||
pitch %= 12;
|
||||
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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user