mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 19:23:59 +00:00
Implement tied notes across all formats, fix some bugs
This commit is contained in:
parent
7339ccd659
commit
f4ad233be3
|
@ -39,7 +39,7 @@
|
||||||
mmaFile += buf;
|
mmaFile += buf;
|
||||||
song->fMeasures[m].MMAChords(mmas, prop);
|
song->fMeasures[m].MMAChords(mmas, prop);
|
||||||
mmaFile += mmas;
|
mmaFile += mmas;
|
||||||
song->fMeasures[m].MMANotes(mmas, prop);
|
song->fMeasures[m].MMANotes(mmas, prop, song->TiedDuration(m+1));
|
||||||
mmaFile += "\t{ " + mmas + " }\n";
|
mmaFile += "\t{ " + mmas + " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,10 +191,12 @@ void VLNote::LilypondName(std::string & name, VLFraction at, VLFraction prevDur,
|
||||||
dur -= part;
|
dur -= part;
|
||||||
}
|
}
|
||||||
for (size_t i=0; i<durations.size(); ++i) {
|
for (size_t i=0; i<durations.size(); ++i) {
|
||||||
if (i)
|
if (i && fPitch != kNoPitch)
|
||||||
name += " ~ ";
|
name += " ~ ";
|
||||||
name += durations[i];
|
name += durations[i];
|
||||||
}
|
}
|
||||||
|
if (fTied & kTiedWithNext)
|
||||||
|
name += " ~";
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -215,13 +217,21 @@ static struct {
|
||||||
{{0,0}, 0}
|
{{0,0}, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
void VLNote::MMAName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const
|
void VLNote::MMAName(std::string & name, VLFraction at, VLFraction dur, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const
|
||||||
{
|
{
|
||||||
|
if (fTied & kTiedWithPrev) {
|
||||||
|
if (fTied & kTiedWithNext) {
|
||||||
|
name = "~<>~";
|
||||||
|
} else {
|
||||||
|
name = '~';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool useSharps = prop.fKey >= 0;
|
bool useSharps = prop.fKey >= 0;
|
||||||
|
|
||||||
name.clear();
|
name.clear();
|
||||||
VLFraction prevPart(0);
|
VLFraction prevPart(0);
|
||||||
for (VLFraction dur = fDuration; dur.fNum; ) {
|
while (dur.fNum) {
|
||||||
VLFraction part;
|
VLFraction part;
|
||||||
bool grouped = dur==nextDur ||
|
bool grouped = dur==nextDur ||
|
||||||
(prevPart!=0 ? dur==prevPart : dur==prevDur);
|
(prevPart!=0 ? dur==prevPart : dur==prevDur);
|
||||||
|
@ -236,13 +246,16 @@ void VLNote::MMAName(std::string & name, VLFraction at, VLFraction prevDur, VLFr
|
||||||
dur -= part;
|
dur -= part;
|
||||||
at += part;
|
at += part;
|
||||||
}
|
}
|
||||||
name += MMAPitchName(fPitch, useSharps);
|
int pitch = fTied & kTiedWithPrev ? kNoPitch : fPitch;
|
||||||
if (fPitch != kNoPitch) {
|
name += MMAPitchName(pitch, useSharps);
|
||||||
for (int raise = (fPitch-kMiddleC)/kOctave; raise>0; --raise)
|
if (pitch != kNoPitch) {
|
||||||
|
for (int raise = (pitch-kMiddleC)/kOctave; raise>0; --raise)
|
||||||
name += '+';
|
name += '+';
|
||||||
for (int lower = (kMiddleC-fPitch)/kOctave; lower>0; --lower)
|
for (int lower = (kMiddleC-pitch)/kOctave; lower>0; --lower)
|
||||||
name += '-';
|
name += '-';
|
||||||
}
|
}
|
||||||
|
if (fTied & kTiedWithNext)
|
||||||
|
name += '~';
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VLChordModifier {
|
struct VLChordModifier {
|
||||||
|
@ -755,7 +768,8 @@ VLMeasure::VLMeasure()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop) const
|
void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop,
|
||||||
|
VLFraction extra) const
|
||||||
{
|
{
|
||||||
VLFraction at(0);
|
VLFraction at(0);
|
||||||
VLNoteList::const_iterator i = fMelody.begin();
|
VLNoteList::const_iterator i = fMelody.begin();
|
||||||
|
@ -766,15 +780,23 @@ void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop) const
|
||||||
for (; i!=e; ++i) {
|
for (; i!=e; ++i) {
|
||||||
std::string note;
|
std::string note;
|
||||||
VLFraction nextDur(0);
|
VLFraction nextDur(0);
|
||||||
|
VLFraction dur(i->fDuration);
|
||||||
VLNoteList::const_iterator n=i;
|
VLNoteList::const_iterator n=i;
|
||||||
if (++n != e)
|
if (++n != e)
|
||||||
nextDur = n->fDuration;
|
nextDur = n->fDuration;
|
||||||
i->MMAName(note, at, prevDur, nextDur, prop);
|
else
|
||||||
if (notes.size())
|
dur += extra;
|
||||||
|
i->MMAName(note, at, dur, prevDur, nextDur, prop);
|
||||||
|
if (notes.size()>1)
|
||||||
notes += ' ';
|
notes += ' ';
|
||||||
|
if (note == "~")
|
||||||
|
notes += note;
|
||||||
|
else
|
||||||
notes += note+';';
|
notes += note+';';
|
||||||
at += i->fDuration;
|
at += i->fDuration;
|
||||||
}
|
}
|
||||||
|
if (notes == "~")
|
||||||
|
notes += "<>;";
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLMeasure::MMAChords(std::string & chords, const VLProperties & prop) const
|
void VLMeasure::MMAChords(std::string & chords, const VLProperties & prop) const
|
||||||
|
@ -934,8 +956,6 @@ void VLSong::AddNote(VLLyricsNote note, size_t measure, VLFraction at)
|
||||||
//
|
//
|
||||||
// Overlap, split current
|
// Overlap, split current
|
||||||
//
|
//
|
||||||
if (i->fTied & VLNote::kTiedWithPrev)
|
|
||||||
LastTie(fMeasures[measure-1]) &= ~VLNote::kTiedWithNext;
|
|
||||||
note.fDuration = tEnd-at;
|
note.fDuration = tEnd-at;
|
||||||
i->fDuration = at-t;
|
i->fDuration = at-t;
|
||||||
i = fMeasures[measure].fMelody.insert(++i, note);
|
i = fMeasures[measure].fMelody.insert(++i, note);
|
||||||
|
@ -1035,7 +1055,7 @@ void VLSong::ExtendNote(size_t measure, VLFraction at)
|
||||||
//
|
//
|
||||||
k->fPitch = i->fPitch;
|
k->fPitch = i->fPitch;
|
||||||
k->fTied = VLNote::kTiedWithPrev;
|
k->fTied = VLNote::kTiedWithPrev;
|
||||||
i->fTied != VLNote::kTiedWithNext;
|
i->fTied |= VLNote::kTiedWithNext;
|
||||||
k->fLyrics.clear();
|
k->fLyrics.clear();
|
||||||
if (wasTied) {
|
if (wasTied) {
|
||||||
//
|
//
|
||||||
|
@ -2007,3 +2027,19 @@ void VLSong::DeleteMeasures(size_t beginMeasure, size_t endMeasure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VLFract VLSong::TiedDuration(size_t measure)
|
||||||
|
{
|
||||||
|
VLFraction total(0);
|
||||||
|
|
||||||
|
while (measure < fMeasures.size()) {
|
||||||
|
VLNote n = fMeasures[measure++].fMelody.front();
|
||||||
|
|
||||||
|
if (!(n.fTied & VLNote::kTiedWithPrev))
|
||||||
|
break;
|
||||||
|
total += n.fDuration;
|
||||||
|
if (!(n.fTied & VLNote::kTiedWithNext))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ struct VLNote {
|
||||||
|
|
||||||
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, VLFraction prevDur, VLFraction nextDur, bool & triplet, 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;
|
void MMAName(std::string & name, VLFraction at, VLFraction dur, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VLRest : VLNote {
|
struct VLRest : VLNote {
|
||||||
|
@ -244,7 +244,7 @@ struct VLMeasure {
|
||||||
|
|
||||||
VLMeasure();
|
VLMeasure();
|
||||||
|
|
||||||
void MMANotes(std::string & notes, const VLProperties & prop) const;
|
void MMANotes(std::string & notes, const VLProperties & prop, VLFraction extra) const;
|
||||||
void MMAChords(std::string & chords, const VLProperties & prop) const;
|
void MMAChords(std::string & chords, const VLProperties & prop) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,6 +354,7 @@ struct VLSong {
|
||||||
void LilypondNotes(std::string & notes) const;
|
void LilypondNotes(std::string & notes) const;
|
||||||
void LilypondChords(std::string & chords) const;
|
void LilypondChords(std::string & chords) const;
|
||||||
void LilypondStanza(std::string & lyrics, size_t stanza) const;
|
void LilypondStanza(std::string & lyrics, size_t stanza) const;
|
||||||
|
VLFract TiedDuration(size_t measure);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
|
@ -299,7 +299,7 @@
|
||||||
VLNoteList::const_iterator next = note;
|
VLNoteList::const_iterator next = note;
|
||||||
if (++next != melody.end())
|
if (++next != melody.end())
|
||||||
nextDur = next->fDuration;
|
nextDur = next->fDuration;
|
||||||
BOOL first = !m || !note->fTied;
|
BOOL first = !m || !(note->fTied & VLNote::kTiedWithPrev);
|
||||||
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
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
|
|
||||||
const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
||||||
|
|
||||||
- (NSXMLElement *)noteWithPitch:(int)pitch duration:(int)units useSharps:(BOOL)useSharps
|
- (NSXMLElement *)noteWithPitch:(int)pitch duration:(int)units useSharps:(BOOL)useSharps tied:(int)tied
|
||||||
{
|
{
|
||||||
NSXMLElement * note = [NSXMLNode elementWithName:@"note"];
|
NSXMLElement * note = [NSXMLNode elementWithName:@"note"];
|
||||||
if (pitch == VLNote::kNoPitch) {
|
if (pitch == VLNote::kNoPitch) {
|
||||||
|
@ -140,6 +140,18 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
||||||
[note addChild: [NSXMLNode elementWithName:@"duration"
|
[note addChild: [NSXMLNode elementWithName:@"duration"
|
||||||
stringValue: [NSString stringWithFormat:@"%d",
|
stringValue: [NSString stringWithFormat:@"%d",
|
||||||
units]]];
|
units]]];
|
||||||
|
if (tied & VLNote::kTiedWithPrev) {
|
||||||
|
NSXMLElement * tie = [NSXMLNode elementWithName:@"tie"];
|
||||||
|
[tie addAttribute: [NSXMLNode attributeWithName:@"type"
|
||||||
|
stringValue:@"stop"]];
|
||||||
|
[note addChild:tie];
|
||||||
|
}
|
||||||
|
if (tied & VLNote::kTiedWithNext) {
|
||||||
|
NSXMLElement * tie = [NSXMLNode elementWithName:@"tie"];
|
||||||
|
[tie addAttribute: [NSXMLNode attributeWithName:@"type"
|
||||||
|
stringValue:@"start"]];
|
||||||
|
[note addChild:tie];
|
||||||
|
}
|
||||||
[note addChild: [NSXMLNode elementWithName:@"voice"
|
[note addChild: [NSXMLNode elementWithName:@"voice"
|
||||||
stringValue: @"1"]];
|
stringValue: @"1"]];
|
||||||
|
|
||||||
|
@ -189,7 +201,8 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
||||||
VLFraction u = note->fDuration / resolution;
|
VLFraction u = note->fDuration / resolution;
|
||||||
int units = (u.fNum+u.fDenom/2)/u.fDenom;
|
int units = (u.fNum+u.fDenom/2)/u.fDenom;
|
||||||
NSXMLElement*n =
|
NSXMLElement*n =
|
||||||
[self noteWithPitch:note->fPitch duration:units useSharps:useSharps];
|
[self noteWithPitch:note->fPitch duration:units useSharps:useSharps
|
||||||
|
tied:note->fTied];
|
||||||
for (size_t i=0; i<note->fLyrics.size(); ++i)
|
for (size_t i=0; i<note->fLyrics.size(); ++i)
|
||||||
if (note->fLyrics[i])
|
if (note->fLyrics[i])
|
||||||
[n addChild:[self syllable:¬e->fLyrics[i] inStanza:i+1]];
|
[n addChild:[self syllable:¬e->fLyrics[i] inStanza:i+1]];
|
||||||
|
@ -210,12 +223,12 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
||||||
int units = (u.fNum+u.fDenom/2)/u.fDenom;
|
int units = (u.fNum+u.fDenom/2)/u.fDenom;
|
||||||
NSXMLElement* ch = nil;
|
NSXMLElement* ch = nil;
|
||||||
if (chord->fPitch == VLNote::kNoPitch) {
|
if (chord->fPitch == VLNote::kNoPitch) {
|
||||||
[meas addChild:[self noteWithPitch:chord->fPitch duration:units useSharps:useSharps]];
|
[meas addChild:[self noteWithPitch:chord->fPitch duration:units useSharps:useSharps tied:0]];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (chord->fRootPitch != VLNote::kNoPitch) {
|
if (chord->fRootPitch != VLNote::kNoPitch) {
|
||||||
[meas addChild:[self noteWithPitch:chord->fRootPitch
|
[meas addChild:[self noteWithPitch:chord->fRootPitch
|
||||||
duration:units useSharps:useSharps]];
|
duration:units useSharps:useSharps tied:0]];
|
||||||
ch = [NSXMLNode elementWithName:@"chord"];
|
ch = [NSXMLNode elementWithName:@"chord"];
|
||||||
}
|
}
|
||||||
for (int step=0; step<32; ++step)
|
for (int step=0; step<32; ++step)
|
||||||
|
@ -224,7 +237,7 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
|
||||||
} else if (chord->fSteps & (1 << step)) {
|
} else if (chord->fSteps & (1 << step)) {
|
||||||
NSXMLElement * note =
|
NSXMLElement * note =
|
||||||
[self noteWithPitch:chord->fPitch+step
|
[self noteWithPitch:chord->fPitch+step
|
||||||
duration:units useSharps:useSharps];
|
duration:units useSharps:useSharps tied:0];
|
||||||
[note insertChild:ch atIndex:0];
|
[note insertChild:ch atIndex:0];
|
||||||
[meas addChild: note];
|
[meas addChild: note];
|
||||||
ch = [NSXMLNode elementWithName:@"chord"];
|
ch = [NSXMLNode elementWithName:@"chord"];
|
||||||
|
@ -494,6 +507,8 @@ int8_t sStepToPitch[] = {
|
||||||
n.fPitch += [[alter stringValue] intValue];
|
n.fPitch += [[alter stringValue] intValue];
|
||||||
}
|
}
|
||||||
n.fDuration = VLFraction([note intForXPath:@"./duration" error:&outError])*unit;
|
n.fDuration = VLFraction([note intForXPath:@"./duration" error:&outError])*unit;
|
||||||
|
if ([note nodeForXPath:@".//tie[@type=\"stop\"]" error:&outError])
|
||||||
|
n.fTied |= VLNote::kTiedWithPrev;
|
||||||
NSEnumerator * e = [[note elementsForName:@"lyric"] objectEnumerator];
|
NSEnumerator * e = [[note elementsForName:@"lyric"] objectEnumerator];
|
||||||
for (NSXMLElement * lyric; lyric = [e nextObject]; ) {
|
for (NSXMLElement * lyric; lyric = [e nextObject]; ) {
|
||||||
int stanza = [[[lyric attributeForName:@"number"]
|
int stanza = [[[lyric attributeForName:@"number"]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user