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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (fPitch != kNoPitch) {
|
||||
|
@ -173,9 +173,10 @@ void VLNote::LilypondName(std::string & name, VLFraction at, const VLProperties
|
|||
for (VLFraction dur = fDuration; dur.fNum; ) {
|
||||
char duration[32];
|
||||
VLFraction part, visual;
|
||||
bool triplet;
|
||||
prop.PartialNote(at, dur, &part);
|
||||
prop.VisualNote(at, part, &visual, &triplet);
|
||||
bool grouped = dur==nextDur ||
|
||||
(prevPart!=0 ? dur==prevPart : dur==prevDur);
|
||||
prop.PartialNote(at, dur, grouped, &part);
|
||||
prop.VisualNote(at, part, triplet, &visual, &triplet);
|
||||
if (!triplet && fPitch != kNoPitch && part == dur && 2*visual == prevPart) {
|
||||
durations.pop_back();
|
||||
sprintf(duration, "%s%d.", n.c_str(), visual.fDenom/2);
|
||||
|
@ -214,20 +215,24 @@ static struct {
|
|||
{{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;
|
||||
|
||||
name.clear();
|
||||
VLFraction prevPart(0);
|
||||
for (VLFraction dur = fDuration; dur.fNum; ) {
|
||||
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)
|
||||
if (part == sMMADur[d].fVal) {
|
||||
if (name.size())
|
||||
name += '+';
|
||||
name += sMMADur[d].fName;
|
||||
}
|
||||
prevPart = part;
|
||||
dur -= part;
|
||||
at += part;
|
||||
}
|
||||
|
@ -448,7 +453,7 @@ void VLChord::LilypondName(std::string & name, bool useSharps) const
|
|||
{
|
||||
name = LilypondPitchName(fPitch, useSharps);
|
||||
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);
|
||||
else
|
||||
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,
|
||||
VLFraction * noteDuration) const
|
||||
bool grouped, VLFraction * noteDuration) const
|
||||
{
|
||||
const VLFraction kBeat(1, fTime.fDenom);
|
||||
|
||||
|
@ -706,11 +711,20 @@ void VLProperties::PartialNote(VLFraction at, VLFraction totalDuration,
|
|||
else
|
||||
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))
|
||||
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,
|
||||
bool prevTriplet,
|
||||
VLFraction *visualDur, bool * triplet) const
|
||||
{
|
||||
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) {
|
||||
*visualDur = swung;
|
||||
*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;
|
||||
*triplet = false;
|
||||
} else {
|
||||
*visualDur = 4*actualDur/3;
|
||||
*visualDur = 3*actualDur/2;
|
||||
}
|
||||
} else {
|
||||
*visualDur = 4*actualDur/3;
|
||||
*visualDur = 3*actualDur/2;
|
||||
}
|
||||
} else {
|
||||
*visualDur = actualDur;
|
||||
|
@ -748,9 +762,14 @@ void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop) const
|
|||
VLNoteList::const_iterator e = fMelody.end();
|
||||
|
||||
notes.clear();
|
||||
VLFraction prevDur(0);
|
||||
for (; i!=e; ++i) {
|
||||
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())
|
||||
notes += ' ';
|
||||
notes += note+';';
|
||||
|
@ -1087,12 +1106,28 @@ void VLSong::LilypondNotes(std::string & notes) const
|
|||
indent = "";
|
||||
}
|
||||
notes += indent;
|
||||
VLFraction prevDur(0);
|
||||
bool triplet = false;
|
||||
for (; i!=e; ++i) {
|
||||
std::string note;
|
||||
i->LilypondName(note, at, fProperties[fMeasures[measure].fPropIdx]);
|
||||
VLNoteList::const_iterator n = i;
|
||||
VLFraction nextDur(0);
|
||||
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 += '|';
|
||||
if (!(measure % 4)) {
|
||||
char measNo[8];
|
||||
|
|
|
@ -139,8 +139,8 @@ struct VLNote {
|
|||
VLNote(std::string name);
|
||||
|
||||
void Name(std::string & name, bool useSharps = false) const;
|
||||
void LilypondName(std::string & name, VLFraction at, const VLProperties & prop) const;
|
||||
void MMAName(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, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const;
|
||||
};
|
||||
|
||||
struct VLRest : VLNote {
|
||||
|
@ -214,11 +214,11 @@ struct VLProperties {
|
|||
//
|
||||
// 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
|
||||
//
|
||||
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 {
|
||||
|
|
|
@ -258,20 +258,26 @@
|
|||
const VLMeasure measure = song->fMeasures[measIdx];
|
||||
const VLNoteList & melody = measure.fMelody;
|
||||
VLFraction at(0);
|
||||
VLFraction prevDur(0);
|
||||
bool triplet = false;
|
||||
for (VLNoteList::const_iterator note = melody.begin();
|
||||
note != melody.end();
|
||||
++note
|
||||
) {
|
||||
VLFraction dur = note->fDuration;
|
||||
VLFraction nextDur(0);
|
||||
VLNoteList::const_iterator next = note;
|
||||
if (++next != melody.end())
|
||||
nextDur = next->fDuration;
|
||||
BOOL first = !m || !note->fTied;
|
||||
int pitch = note->fPitch;
|
||||
while (dur > 0) {
|
||||
VLFraction partialDur; // Actual value of note drawn
|
||||
VLFraction noteDur; // Visual value of note
|
||||
bool triplet;
|
||||
prop.PartialNote(at, dur, &partialDur);
|
||||
prop.VisualNote(at, partialDur, ¬eDur, &triplet);
|
||||
|
||||
prop.PartialNote(at, dur, dur==prevDur || dur==nextDur,
|
||||
&partialDur);
|
||||
prop.VisualNote(at, partialDur, triplet, ¬eDur, &triplet);
|
||||
prevDur = partialDur;
|
||||
if (pitch != VLNote::kNoPitch) {
|
||||
VLMusicElement accidental;
|
||||
NSPoint pos =
|
||||
|
|
Loading…
Reference in New Issue
Block a user