Implement tied notes across all formats, fix some bugs

This commit is contained in:
Matthias Neeracher 2007-04-22 06:20:17 +00:00
parent 7339ccd659
commit f4ad233be3
5 changed files with 75 additions and 23 deletions

View File

@ -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";
} }

View File

@ -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;
}

View File

@ -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:

View File

@ -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

View File

@ -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:&note->fLyrics[i] inStanza:i+1]]; [n addChild:[self syllable:&note->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"]