mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 19:23:59 +00:00
Fix triplet handling
This commit is contained in:
parent
9206a311b6
commit
3d880853b3
|
@ -158,7 +158,7 @@ void VLNote::Name(std::string & name, bool useSharps) const
|
||||||
name = PitchName(fPitch, useSharps);
|
name = PitchName(fPitch, useSharps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLNote::LilypondName(std::string & name, VLFraction at, const VLProperties & prop) const
|
void VLNote::LilypondName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, bool & triplet, const VLProperties & prop) const
|
||||||
{
|
{
|
||||||
std::string n = LilypondPitchName(fPitch, prop.fKey >= 0);
|
std::string n = LilypondPitchName(fPitch, prop.fKey >= 0);
|
||||||
if (fPitch != kNoPitch) {
|
if (fPitch != kNoPitch) {
|
||||||
|
@ -173,9 +173,10 @@ void VLNote::LilypondName(std::string & name, VLFraction at, const VLProperties
|
||||||
for (VLFraction dur = fDuration; dur.fNum; ) {
|
for (VLFraction dur = fDuration; dur.fNum; ) {
|
||||||
char duration[32];
|
char duration[32];
|
||||||
VLFraction part, visual;
|
VLFraction part, visual;
|
||||||
bool triplet;
|
bool grouped = dur==nextDur ||
|
||||||
prop.PartialNote(at, dur, &part);
|
(prevPart!=0 ? dur==prevPart : dur==prevDur);
|
||||||
prop.VisualNote(at, part, &visual, &triplet);
|
prop.PartialNote(at, dur, grouped, &part);
|
||||||
|
prop.VisualNote(at, part, triplet, &visual, &triplet);
|
||||||
if (!triplet && fPitch != kNoPitch && part == dur && 2*visual == prevPart) {
|
if (!triplet && fPitch != kNoPitch && part == dur && 2*visual == prevPart) {
|
||||||
durations.pop_back();
|
durations.pop_back();
|
||||||
sprintf(duration, "%s%d.", n.c_str(), visual.fDenom/2);
|
sprintf(duration, "%s%d.", n.c_str(), visual.fDenom/2);
|
||||||
|
@ -214,22 +215,26 @@ static struct {
|
||||||
{{0,0}, 0}
|
{{0,0}, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
void VLNote::MMAName(std::string & name, VLFraction at, const VLProperties & prop) const
|
void VLNote::MMAName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const
|
||||||
{
|
{
|
||||||
bool useSharps = prop.fKey >= 0;
|
bool useSharps = prop.fKey >= 0;
|
||||||
|
|
||||||
name.clear();
|
name.clear();
|
||||||
|
VLFraction prevPart(0);
|
||||||
for (VLFraction dur = fDuration; dur.fNum; ) {
|
for (VLFraction dur = fDuration; dur.fNum; ) {
|
||||||
VLFraction part;
|
VLFraction part;
|
||||||
prop.PartialNote(at, dur, &part);
|
bool grouped = dur==nextDur ||
|
||||||
|
(prevPart!=0 ? dur==prevPart : dur==prevDur);
|
||||||
|
prop.PartialNote(at, dur, grouped, &part);
|
||||||
for (int d=0; sMMADur[d].fName; ++d)
|
for (int d=0; sMMADur[d].fName; ++d)
|
||||||
if (part == sMMADur[d].fVal) {
|
if (part == sMMADur[d].fVal) {
|
||||||
if (name.size())
|
if (name.size())
|
||||||
name += '+';
|
name += '+';
|
||||||
name += sMMADur[d].fName;
|
name += sMMADur[d].fName;
|
||||||
}
|
}
|
||||||
dur -= part;
|
prevPart = part;
|
||||||
at += part;
|
dur -= part;
|
||||||
|
at += part;
|
||||||
}
|
}
|
||||||
name += MMAPitchName(fPitch, useSharps);
|
name += MMAPitchName(fPitch, useSharps);
|
||||||
if (fPitch != kNoPitch) {
|
if (fPitch != kNoPitch) {
|
||||||
|
@ -448,7 +453,7 @@ void VLChord::LilypondName(std::string & name, bool useSharps) const
|
||||||
{
|
{
|
||||||
name = LilypondPitchName(fPitch, useSharps);
|
name = LilypondPitchName(fPitch, useSharps);
|
||||||
char duration[16];
|
char duration[16];
|
||||||
if (fDuration.fNum == 1 && !(fDuration.fDenom & (fDuration.fDenom-1)))
|
if (fDuration.fNum == 1 && !(fDuration.fDenom & (fDuration.fDenom-1))) // Power of two
|
||||||
sprintf(duration, "%d", fDuration.fDenom);
|
sprintf(duration, "%d", fDuration.fDenom);
|
||||||
else
|
else
|
||||||
sprintf(duration, "1*%d/%d", fDuration.fNum, fDuration.fDenom);
|
sprintf(duration, "1*%d/%d", fDuration.fNum, fDuration.fDenom);
|
||||||
|
@ -687,7 +692,7 @@ static void TrimNote(VLFraction at, VLFraction & d, VLFraction grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLProperties::PartialNote(VLFraction at, VLFraction totalDuration,
|
void VLProperties::PartialNote(VLFraction at, VLFraction totalDuration,
|
||||||
VLFraction * noteDuration) const
|
bool grouped, VLFraction * noteDuration) const
|
||||||
{
|
{
|
||||||
const VLFraction kBeat(1, fTime.fDenom);
|
const VLFraction kBeat(1, fTime.fDenom);
|
||||||
|
|
||||||
|
@ -706,11 +711,20 @@ void VLProperties::PartialNote(VLFraction at, VLFraction totalDuration,
|
||||||
else
|
else
|
||||||
TrimNote(at, *noteDuration, kBeat);// Don't let other notes span beats
|
TrimNote(at, *noteDuration, kBeat);// Don't let other notes span beats
|
||||||
}
|
}
|
||||||
if (!(noteDuration->fDenom % 3) && *noteDuration != totalDuration && ((at+*noteDuration)%kBeat) > 0)
|
if (!(noteDuration->fDenom % 3))
|
||||||
*noteDuration *= VLFraction(3,4); // avoid frivolous triplets
|
if (*noteDuration != totalDuration) {
|
||||||
|
if (((at+*noteDuration)%kBeat) > 0)
|
||||||
|
*noteDuration *= VLFraction(3,4); // avoid frivolous triplets
|
||||||
|
} else if (*noteDuration > VLFraction(1,4*fDivisions) && !grouped) {
|
||||||
|
if (*noteDuration == VLFraction(1,2*fDivisions))
|
||||||
|
if (at % VLFraction(1, 4*fDivisions/3) == 0)
|
||||||
|
return; // Permit larger swing notes
|
||||||
|
*noteDuration *= VLFraction(3,4); // avoid other isolated triplets
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLProperties::VisualNote(VLFraction at, VLFraction actualDur,
|
void VLProperties::VisualNote(VLFraction at, VLFraction actualDur,
|
||||||
|
bool prevTriplet,
|
||||||
VLFraction *visualDur, bool * triplet) const
|
VLFraction *visualDur, bool * triplet) const
|
||||||
{
|
{
|
||||||
bool swing= !(fDivisions % 3); // In swing mode?
|
bool swing= !(fDivisions % 3); // In swing mode?
|
||||||
|
@ -722,14 +736,14 @@ void VLProperties::VisualNote(VLFraction at, VLFraction actualDur,
|
||||||
if (actualDur == 4*swung/3 && (at % swingGrid) == 0) {
|
if (actualDur == 4*swung/3 && (at % swingGrid) == 0) {
|
||||||
*visualDur = swung;
|
*visualDur = swung;
|
||||||
*triplet = false;
|
*triplet = false;
|
||||||
} else if (actualDur == 2*swung/3 && ((at+actualDur) % swingGrid) == 0) {
|
} else if (actualDur == 2*swung/3 && ((at+actualDur) % swingGrid) == 0 && !prevTriplet) {
|
||||||
*visualDur = swung;
|
*visualDur = swung;
|
||||||
*triplet = false;
|
*triplet = false;
|
||||||
} else {
|
} else {
|
||||||
*visualDur = 4*actualDur/3;
|
*visualDur = 3*actualDur/2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*visualDur = 4*actualDur/3;
|
*visualDur = 3*actualDur/2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*visualDur = actualDur;
|
*visualDur = actualDur;
|
||||||
|
@ -748,9 +762,14 @@ void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop) const
|
||||||
VLNoteList::const_iterator e = fMelody.end();
|
VLNoteList::const_iterator e = fMelody.end();
|
||||||
|
|
||||||
notes.clear();
|
notes.clear();
|
||||||
|
VLFraction prevDur(0);
|
||||||
for (; i!=e; ++i) {
|
for (; i!=e; ++i) {
|
||||||
std::string note;
|
std::string note;
|
||||||
i->MMAName(note, at, prop);
|
VLFraction nextDur(0);
|
||||||
|
VLNoteList::const_iterator n=i;
|
||||||
|
if (++n != e)
|
||||||
|
nextDur = n->fDuration;
|
||||||
|
i->MMAName(note, at, prevDur, nextDur, prop);
|
||||||
if (notes.size())
|
if (notes.size())
|
||||||
notes += ' ';
|
notes += ' ';
|
||||||
notes += note+';';
|
notes += note+';';
|
||||||
|
@ -1087,12 +1106,28 @@ void VLSong::LilypondNotes(std::string & notes) const
|
||||||
indent = "";
|
indent = "";
|
||||||
}
|
}
|
||||||
notes += indent;
|
notes += indent;
|
||||||
|
VLFraction prevDur(0);
|
||||||
|
bool triplet = false;
|
||||||
for (; i!=e; ++i) {
|
for (; i!=e; ++i) {
|
||||||
std::string note;
|
std::string note;
|
||||||
i->LilypondName(note, at, fProperties[fMeasures[measure].fPropIdx]);
|
VLNoteList::const_iterator n = i;
|
||||||
at += i->fDuration;
|
VLFraction nextDur(0);
|
||||||
notes += note+" ";
|
if (++n != e)
|
||||||
|
nextDur = n->fDuration;
|
||||||
|
i->LilypondName(note, at, prevDur, nextDur, triplet, fProperties[fMeasures[measure].fPropIdx]);
|
||||||
|
prevDur = i->fDuration;
|
||||||
|
at += i->fDuration;
|
||||||
|
notes += note+" ";
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Consolidate triplets
|
||||||
|
//
|
||||||
|
size_t trip;
|
||||||
|
while ((trip = notes.find("} \\times 2/3 { ")) != std::string::npos)
|
||||||
|
notes.erase(trip, 15);
|
||||||
|
while ((trip = notes.find("} ~ \\times 2/3 { ")) != std::string::npos)
|
||||||
|
notes.replace(trip, 17, "~ ", 2);
|
||||||
|
|
||||||
notes += '|';
|
notes += '|';
|
||||||
if (!(measure % 4)) {
|
if (!(measure % 4)) {
|
||||||
char measNo[8];
|
char measNo[8];
|
||||||
|
|
|
@ -139,8 +139,8 @@ struct VLNote {
|
||||||
VLNote(std::string name);
|
VLNote(std::string name);
|
||||||
|
|
||||||
void Name(std::string & name, bool useSharps = false) const;
|
void Name(std::string & name, bool useSharps = false) const;
|
||||||
void LilypondName(std::string & name, VLFraction at, const VLProperties & prop) const;
|
void LilypondName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, bool & triplet, const VLProperties & prop) const;
|
||||||
void MMAName(std::string & name, VLFraction at, const VLProperties & prop) const;
|
void MMAName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VLRest : VLNote {
|
struct VLRest : VLNote {
|
||||||
|
@ -214,11 +214,11 @@ struct VLProperties {
|
||||||
//
|
//
|
||||||
// Subdivide a note and adjust for swing
|
// Subdivide a note and adjust for swing
|
||||||
//
|
//
|
||||||
void PartialNote(VLFraction at, VLFraction totalDuration, VLFraction * noteDuration) const;
|
void PartialNote(VLFraction at, VLFraction totalDuration, bool grouped, VLFraction * noteDuration) const;
|
||||||
//
|
//
|
||||||
// Determine visual representation of note head
|
// Determine visual representation of note head
|
||||||
//
|
//
|
||||||
void VisualNote(VLFraction at, VLFraction actualDur, VLFraction *visualDur, bool * triplet) const;
|
void VisualNote(VLFraction at, VLFraction actualDur, bool prevTriplet, VLFraction *visualDur, bool * triplet) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VLLyricsNote : VLNote {
|
struct VLLyricsNote : VLNote {
|
||||||
|
|
|
@ -258,20 +258,26 @@
|
||||||
const VLMeasure measure = song->fMeasures[measIdx];
|
const VLMeasure measure = song->fMeasures[measIdx];
|
||||||
const VLNoteList & melody = measure.fMelody;
|
const VLNoteList & melody = measure.fMelody;
|
||||||
VLFraction at(0);
|
VLFraction at(0);
|
||||||
|
VLFraction prevDur(0);
|
||||||
|
bool triplet = false;
|
||||||
for (VLNoteList::const_iterator note = melody.begin();
|
for (VLNoteList::const_iterator note = melody.begin();
|
||||||
note != melody.end();
|
note != melody.end();
|
||||||
++note
|
++note
|
||||||
) {
|
) {
|
||||||
VLFraction dur = note->fDuration;
|
VLFraction dur = note->fDuration;
|
||||||
|
VLFraction nextDur(0);
|
||||||
|
VLNoteList::const_iterator next = note;
|
||||||
|
if (++next != melody.end())
|
||||||
|
nextDur = next->fDuration;
|
||||||
BOOL first = !m || !note->fTied;
|
BOOL first = !m || !note->fTied;
|
||||||
int pitch = note->fPitch;
|
int pitch = note->fPitch;
|
||||||
while (dur > 0) {
|
while (dur > 0) {
|
||||||
VLFraction partialDur; // Actual value of note drawn
|
VLFraction partialDur; // Actual value of note drawn
|
||||||
VLFraction noteDur; // Visual value of note
|
VLFraction noteDur; // Visual value of note
|
||||||
bool triplet;
|
prop.PartialNote(at, dur, dur==prevDur || dur==nextDur,
|
||||||
prop.PartialNote(at, dur, &partialDur);
|
&partialDur);
|
||||||
prop.VisualNote(at, partialDur, ¬eDur, &triplet);
|
prop.VisualNote(at, partialDur, triplet, ¬eDur, &triplet);
|
||||||
|
prevDur = partialDur;
|
||||||
if (pitch != VLNote::kNoPitch) {
|
if (pitch != VLNote::kNoPitch) {
|
||||||
VLMusicElement accidental;
|
VLMusicElement accidental;
|
||||||
NSPoint pos =
|
NSPoint pos =
|
||||||
|
|
Loading…
Reference in New Issue
Block a user