mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +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;
|
||||
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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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 += ' ';
|
||||
notes += note+';';
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:¬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;
|
||||
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"]
|
||||
|
|
Loading…
Reference in New Issue
Block a user