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;
song->fMeasures[m].MMAChords(mmas, prop);
mmaFile += mmas;
song->fMeasures[m].MMANotes(mmas, prop);
song->fMeasures[m].MMANotes(mmas, prop, song->TiedDuration(m+1));
mmaFile += "\t{ " + mmas + " }\n";
}

View File

@ -191,10 +191,12 @@ void VLNote::LilypondName(std::string & name, VLFraction at, VLFraction prevDur,
dur -= part;
}
for (size_t i=0; i<durations.size(); ++i) {
if (i)
if (i && fPitch != kNoPitch)
name += " ~ ";
name += durations[i];
}
if (fTied & kTiedWithNext)
name += " ~";
}
static struct {
@ -215,13 +217,21 @@ static struct {
{{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;
name.clear();
VLFraction prevPart(0);
for (VLFraction dur = fDuration; dur.fNum; ) {
while (dur.fNum) {
VLFraction part;
bool grouped = dur==nextDur ||
(prevPart!=0 ? dur==prevPart : dur==prevDur);
@ -236,13 +246,16 @@ void VLNote::MMAName(std::string & name, VLFraction at, VLFraction prevDur, VLFr
dur -= part;
at += part;
}
name += MMAPitchName(fPitch, useSharps);
if (fPitch != kNoPitch) {
for (int raise = (fPitch-kMiddleC)/kOctave; raise>0; --raise)
int pitch = fTied & kTiedWithPrev ? kNoPitch : fPitch;
name += MMAPitchName(pitch, useSharps);
if (pitch != kNoPitch) {
for (int raise = (pitch-kMiddleC)/kOctave; raise>0; --raise)
name += '+';
for (int lower = (kMiddleC-fPitch)/kOctave; lower>0; --lower)
for (int lower = (kMiddleC-pitch)/kOctave; lower>0; --lower)
name += '-';
}
if (fTied & kTiedWithNext)
name += '~';
}
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);
VLNoteList::const_iterator i = fMelody.begin();
@ -766,15 +780,23 @@ void VLMeasure::MMANotes(std::string & notes, const VLProperties & prop) const
for (; i!=e; ++i) {
std::string note;
VLFraction nextDur(0);
VLFraction dur(i->fDuration);
VLNoteList::const_iterator n=i;
if (++n != e)
nextDur = n->fDuration;
i->MMAName(note, at, prevDur, nextDur, prop);
if (notes.size())
else
dur += extra;
i->MMAName(note, at, dur, prevDur, nextDur, prop);
if (notes.size()>1)
notes += ' ';
if (note == "~")
notes += note;
else
notes += note+';';
at += i->fDuration;
}
if (notes == "~")
notes += "<>;";
}
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
//
if (i->fTied & VLNote::kTiedWithPrev)
LastTie(fMeasures[measure-1]) &= ~VLNote::kTiedWithNext;
note.fDuration = tEnd-at;
i->fDuration = at-t;
i = fMeasures[measure].fMelody.insert(++i, note);
@ -1035,7 +1055,7 @@ void VLSong::ExtendNote(size_t measure, VLFraction at)
//
k->fPitch = i->fPitch;
k->fTied = VLNote::kTiedWithPrev;
i->fTied != VLNote::kTiedWithNext;
i->fTied |= VLNote::kTiedWithNext;
k->fLyrics.clear();
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 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 {
@ -244,7 +244,7 @@ struct 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;
};
@ -354,6 +354,7 @@ struct VLSong {
void LilypondNotes(std::string & notes) const;
void LilypondChords(std::string & chords) const;
void LilypondStanza(std::string & lyrics, size_t stanza) const;
VLFract TiedDuration(size_t measure);
};
// Local Variables:

View File

@ -299,7 +299,7 @@
VLNoteList::const_iterator next = note;
if (++next != melody.end())
nextDur = next->fDuration;
BOOL first = !m || !note->fTied;
BOOL first = !m || !(note->fTied & VLNote::kTiedWithPrev);
int pitch = note->fPitch;
while (dur > 0) {
VLFraction partialDur; // Actual value of note drawn

View File

@ -104,7 +104,7 @@
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"];
if (pitch == VLNote::kNoPitch) {
@ -140,6 +140,18 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
[note addChild: [NSXMLNode elementWithName:@"duration"
stringValue: [NSString stringWithFormat:@"%d",
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"
stringValue: @"1"]];
@ -189,7 +201,8 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
VLFraction u = note->fDuration / resolution;
int units = (u.fNum+u.fDenom/2)/u.fDenom;
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)
if (note->fLyrics[i])
[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;
NSXMLElement* ch = nil;
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;
}
if (chord->fRootPitch != VLNote::kNoPitch) {
[meas addChild:[self noteWithPitch:chord->fRootPitch
duration:units useSharps:useSharps]];
duration:units useSharps:useSharps tied:0]];
ch = [NSXMLNode elementWithName:@"chord"];
}
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)) {
NSXMLElement * note =
[self noteWithPitch:chord->fPitch+step
duration:units useSharps:useSharps];
duration:units useSharps:useSharps tied:0];
[note insertChild:ch atIndex:0];
[meas addChild: note];
ch = [NSXMLNode elementWithName:@"chord"];
@ -494,6 +507,8 @@ int8_t sStepToPitch[] = {
n.fPitch += [[alter stringValue] intValue];
}
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];
for (NSXMLElement * lyric; lyric = [e nextObject]; ) {
int stanza = [[[lyric attributeForName:@"number"]