mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Implement new duration visual model
This commit is contained in:
parent
fd684b8820
commit
a7cf4a28df
|
@ -154,6 +154,11 @@ VLNote::VLNote(std::string name)
|
|||
fPitch = kNoPitch; // Failed to parse completely
|
||||
}
|
||||
|
||||
VLNote::VLNote(VLFraction dur, int pitch)
|
||||
: fDuration(dur), fPitch(pitch), fTied(0), fVisual(0)
|
||||
{
|
||||
}
|
||||
|
||||
void VLNote::Name(std::string & name, bool useSharps) const
|
||||
{
|
||||
name = PitchName(fPitch, useSharps);
|
||||
|
@ -274,6 +279,53 @@ void VLNote::MMAName(std::string & name, VLFraction at, VLFraction dur, VLFracti
|
|||
name += '~';
|
||||
}
|
||||
|
||||
void VLNote::MakeRepresentable()
|
||||
{
|
||||
if (fDuration > 1)
|
||||
fDuration = 1;
|
||||
fVisual = kWhole;
|
||||
VLFraction part(1,1);
|
||||
VLFraction triplet(2,3);
|
||||
//
|
||||
// Power of 2 denominators are not triplets
|
||||
//
|
||||
bool nonTriplet(!(fDuration.fDenom & (fDuration.fDenom-1)));
|
||||
while (part.fDenom < 64) {
|
||||
if (fDuration >= part) {
|
||||
fDuration = part;
|
||||
return;
|
||||
} else if (!nonTriplet && fDuration >= triplet) {
|
||||
fDuration = triplet;
|
||||
fVisual |= kTriplet;
|
||||
return;
|
||||
}
|
||||
part /= 2;
|
||||
triplet /= 2;
|
||||
++fVisual;
|
||||
}
|
||||
fprintf(stderr, "Encountered preposterously brief note: %d/%d\n",
|
||||
fDuration.fNum, fDuration.fDenom);
|
||||
abort();
|
||||
}
|
||||
|
||||
void VLNote::AlignToGrid(VLFraction at, VLFraction grid)
|
||||
{
|
||||
if (at+fDuration > grid) {
|
||||
fDuration = grid-at;
|
||||
MakeRepresentable();
|
||||
}
|
||||
}
|
||||
|
||||
VLLyricsNote::VLLyricsNote(const VLNote & note)
|
||||
: VLNote(note)
|
||||
{
|
||||
}
|
||||
|
||||
VLLyricsNote::VLLyricsNote(VLFraction dur, int pitch)
|
||||
: VLNote(dur, pitch)
|
||||
{
|
||||
}
|
||||
|
||||
struct VLChordModifier {
|
||||
const char * fName;
|
||||
uint32_t fAddSteps;
|
||||
|
@ -313,6 +365,11 @@ static const VLChordModifier kModifiers[] = {
|
|||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
VLChord::VLChord(VLFraction dur, int pitch, int rootPitch)
|
||||
: VLNote(dur, pitch), fSteps(0), fRootPitch(kNoPitch)
|
||||
{
|
||||
}
|
||||
|
||||
VLChord::VLChord(std::string name)
|
||||
{
|
||||
size_t root;
|
||||
|
@ -846,6 +903,141 @@ bool VLMeasure::NoChords() const
|
|||
&& fChords.front().fPitch == VLNote::kNoPitch;
|
||||
}
|
||||
|
||||
void VLMeasure::DecomposeNotes(const VLProperties & prop, VLNoteList & decomposed) const
|
||||
{
|
||||
decomposed.clear();
|
||||
|
||||
const VLFraction kQuarterDur(1,4);
|
||||
const VLFraction kEighthLoc(1,8);
|
||||
const VLFraction kQuarTripLoc(1,6);
|
||||
|
||||
VLFraction at(0);
|
||||
VLNoteList::const_iterator i = fMelody.begin();
|
||||
VLNoteList::const_iterator e = fMelody.end();
|
||||
int prevTriplets = 0;
|
||||
int prevVisual;
|
||||
VLFraction prevTripDur;
|
||||
|
||||
while (i!=e) {
|
||||
VLNoteList::const_iterator n = i;
|
||||
++n;
|
||||
|
||||
VLLyricsNote c = *i; // Current note, remaining duration
|
||||
VLLyricsNote p = c; // Next partial note
|
||||
do {
|
||||
//
|
||||
// Start with longest possible note
|
||||
//
|
||||
p.MakeRepresentable();
|
||||
//
|
||||
// Prefer further triplets
|
||||
//
|
||||
if (prevTriplets) {
|
||||
if (p.fDuration >= 2*prevTripDur) {
|
||||
p.fDuration = 2*prevTripDur;
|
||||
if (prevTriplets == 1) {
|
||||
p.fVisual = prevVisual-1;
|
||||
prevTriplets = 2; // 1/8th, 1/4th triplet or similar
|
||||
} else {
|
||||
p.fDuration = prevTripDur; // 1/8th, 1/8th, 1/4th
|
||||
p.fVisual = prevVisual;
|
||||
}
|
||||
goto haveDuration;
|
||||
} else if (p.fDuration >= prevTripDur) {
|
||||
p.fDuration = prevTripDur;
|
||||
p.fVisual = prevVisual;
|
||||
goto haveDuration;
|
||||
} else if (p.fDuration >= prevTripDur/2) {
|
||||
p.fDuration = prevTripDur/2;
|
||||
p.fVisual = prevVisual+1;
|
||||
prevTripDur /= 2;
|
||||
if (prevTriplets == 1)
|
||||
prevTriplets = 2; // 1/4th, 1/8th
|
||||
else
|
||||
prevTriplets = 1; // 1/4th, 1/4th, 1/8th
|
||||
goto haveDuration;
|
||||
}
|
||||
prevTriplets = 0;
|
||||
}
|
||||
if (at.fDenom > 4) {
|
||||
//
|
||||
// Break up notes not starting on quarter beat
|
||||
// - Never cross middle of measure
|
||||
//
|
||||
VLFraction middle;
|
||||
if (prop.fTime.fNum & 1) // Treat 5/4 as 3+2, not 2+3
|
||||
middle = VLFraction((prop.fTime.fNum+1)/2, prop.fTime.fDenom);
|
||||
else
|
||||
middle = prop.fTime / 2;
|
||||
if (at < middle)
|
||||
p.AlignToGrid(at, middle);
|
||||
VLFraction inBeat = at % kQuarterDur;
|
||||
if ((inBeat == kEighthLoc || inBeat == kQuarTripLoc)
|
||||
&& p.fDuration == kQuarterDur
|
||||
)
|
||||
; // Allow syncopated quarters
|
||||
else
|
||||
p.AlignToGrid(inBeat, kQuarterDur); // Align all others
|
||||
}
|
||||
if (p.fVisual & VLNote::kTriplet) {
|
||||
//
|
||||
// Distinguish swing 8ths/16ths from triplets
|
||||
//
|
||||
VLFraction swung(1, prop.fDivisions < 6 ? 8 : 16);
|
||||
VLFraction grid(2*swung);
|
||||
if (p.fDuration == 4*swung/3 && (at % grid == 0)) {
|
||||
if (p.fDuration == c.fDuration && n!=e
|
||||
&& (n->fDuration == p.fDuration
|
||||
|| (n->fDuration == 2*p.fDuration))
|
||||
) {
|
||||
; // Triplet, not swing note
|
||||
} else {
|
||||
//
|
||||
// First swing note (4th triplet -> 8th)
|
||||
//
|
||||
p.fVisual = (p.fVisual+1) & VLNote::kNoteHead;
|
||||
}
|
||||
} else if (p.fDuration == 2*swung/3
|
||||
&& ((at+p.fDuration) % grid == 0)
|
||||
) {
|
||||
//
|
||||
// Second swing note (8th triplet -> 8th)
|
||||
//
|
||||
p.fVisual &= VLNote::kNoteHead;
|
||||
} else if (p.fDuration != c.fDuration
|
||||
&& 2*p.fDuration != c.fDuration
|
||||
) {
|
||||
//
|
||||
// Get rid of awkward triplets
|
||||
//
|
||||
p.fDuration *= VLFraction(3,4);
|
||||
p.fVisual = (p.fVisual+1) & VLNote::kNoteHead;
|
||||
}
|
||||
}
|
||||
haveDuration:
|
||||
if (p.fVisual & VLNote::kTriplet)
|
||||
if (prevTriplets = (prevTriplets+1)%3) {
|
||||
prevTripDur = p.fDuration;
|
||||
prevVisual = p.fVisual;
|
||||
}
|
||||
p.fTied &= VLNote::kTiedWithPrev;
|
||||
if (p.fDuration == c.fDuration)
|
||||
p.fTied |= c.fTied & VLNote::kTiedWithNext;
|
||||
else
|
||||
p.fTied |= VLNote::kTiedWithNext;
|
||||
if (p.fPitch == VLNote::kNoPitch)
|
||||
p.fTied = VLNote::kNotTied;
|
||||
decomposed.push_back(p);
|
||||
at += p.fDuration;
|
||||
c.fDuration -= p.fDuration;
|
||||
p.fDuration = c.fDuration;
|
||||
p.fTied |= VLNote::kTiedWithPrev;
|
||||
p.fLyrics.clear();
|
||||
} while (c.fDuration > 0);
|
||||
i = n;
|
||||
}
|
||||
}
|
||||
|
||||
VLSong::VLSong(bool initialize)
|
||||
{
|
||||
if (!initialize)
|
||||
|
@ -865,9 +1057,8 @@ VLSong::VLSong(bool initialize)
|
|||
void VLSong::AddMeasure()
|
||||
{
|
||||
VLFraction dur = fProperties.front().fTime;
|
||||
VLLyricsNote rest = VLLyricsNote(VLRest(dur));
|
||||
VLChord rchord;
|
||||
rchord.fDuration = dur;
|
||||
VLLyricsNote rest(dur);
|
||||
VLChord rchord(dur);
|
||||
VLMeasure meas;
|
||||
|
||||
meas.fChords.push_back(rchord);
|
||||
|
@ -1357,9 +1548,8 @@ void VLSong::ChangeTime(VLFraction newTime)
|
|||
VLProperties & prop = fProperties.front();
|
||||
if (prop.fTime == newTime)
|
||||
return; // No change
|
||||
VLChord rchord;
|
||||
rchord.fDuration = newTime-prop.fTime;
|
||||
VLLyricsNote rnote = VLLyricsNote(VLRest(newTime-prop.fTime));
|
||||
VLChord rchord(newTime-prop.fTime);
|
||||
VLLyricsNote rnote(newTime-prop.fTime);
|
||||
for (size_t measure=0; measure<fMeasures.size(); ++measure) {
|
||||
if (newTime < prop.fTime) {
|
||||
VLChordList::iterator i = fMeasures[measure].fChords.begin();
|
||||
|
@ -2255,10 +2445,8 @@ void VLSong::PasteMeasures(size_t beginMeasure, const VLSong & measures, int mod
|
|||
VLMeasure rest;
|
||||
rest.fPropIdx = fMeasures.back().fPropIdx;
|
||||
VLFraction dur = fProperties[rest.fPropIdx].fTime;
|
||||
rest.fMelody.push_back(VLLyricsNote(VLRest(dur)));
|
||||
VLChord rchord;
|
||||
rchord.fDuration= dur;
|
||||
rest.fChords.push_back(rchord);
|
||||
rest.fMelody.push_back(VLLyricsNote(dur));
|
||||
rest.fChords.push_back(VLChord(dur));
|
||||
|
||||
fMeasures.insert(fMeasures.end(), nextMeasure-CountMeasures(), rest);
|
||||
}
|
||||
|
@ -2276,7 +2464,7 @@ void VLSong::PasteMeasures(size_t beginMeasure, const VLSong & measures, int mod
|
|||
void VLSong::DeleteMeasures(size_t beginMeasure, size_t endMeasure, int mode)
|
||||
{
|
||||
if (mode == kOverwriteMelody) {
|
||||
VLLyricsNote rest(VLRest(fProperties.front().fTime));
|
||||
VLLyricsNote rest(fProperties.front().fTime);
|
||||
for (size_t m=beginMeasure; m<endMeasure; ++m) {
|
||||
fMeasures[m].fMelody.clear();
|
||||
fMeasures[m].fMelody.push_back(rest);
|
||||
|
|
|
@ -132,20 +132,28 @@ struct VLNote {
|
|||
kTiedWithNext = 1,
|
||||
kTiedWithPrev = 2
|
||||
};
|
||||
//
|
||||
// Hint at visual representation (Computed in DecomposeNotes)
|
||||
//
|
||||
uint8_t fVisual;
|
||||
enum {
|
||||
kWhole = 0,
|
||||
kHalf = 1,
|
||||
kQuarter = 2,
|
||||
kEighth = 3,
|
||||
k16th = 4,
|
||||
k32nd = 5,
|
||||
|
||||
VLNote() : fPitch(kNoPitch) {}
|
||||
VLNote(VLFraction dur, int8_t pitch)
|
||||
: fDuration(dur), fPitch(pitch), fTied(kNotTied)
|
||||
{}
|
||||
kNoteHead = 0x07,
|
||||
kTriplet = 0x80
|
||||
};
|
||||
VLNote(VLFraction dur=0, int pitch=kNoPitch);
|
||||
VLNote(std::string name);
|
||||
|
||||
void Name(std::string & name, bool useSharps = false) const;
|
||||
void LilypondName(std::string & name, VLFraction at, VLFraction prevDur, VLFraction nextDur, bool & triplet, bool & pickup, const VLProperties & prop) const;
|
||||
void MMAName(std::string & name, VLFraction at, VLFraction dur, VLFraction prevDur, VLFraction nextDur, const VLProperties & prop) const;
|
||||
};
|
||||
|
||||
struct VLRest : VLNote {
|
||||
VLRest(VLFraction duration) : VLNote(duration, kNoPitch) {}
|
||||
void MakeRepresentable();
|
||||
void AlignToGrid(VLFraction at, VLFraction grid);
|
||||
};
|
||||
|
||||
struct VLChord : VLNote {
|
||||
|
@ -199,7 +207,7 @@ struct VLChord : VLNote {
|
|||
};
|
||||
int8_t fRootPitch; // kNoPitch == no root
|
||||
|
||||
VLChord() {}
|
||||
VLChord(VLFraction dur=0, int pitch=kNoPitch, int rootPitch=kNoPitch);
|
||||
VLChord(std::string name);
|
||||
void Name(std::string & base, std::string & ext, std::string & root, bool useSharps = false) const;
|
||||
void LilypondName(std::string & name, bool useSharps = false) const;
|
||||
|
@ -228,9 +236,8 @@ struct VLProperties {
|
|||
};
|
||||
|
||||
struct VLLyricsNote : VLNote {
|
||||
VLLyricsNote() {}
|
||||
explicit VLLyricsNote(const VLNote & note)
|
||||
{ *static_cast<VLNote *>(this) = note; }
|
||||
VLLyricsNote(const VLNote & note);
|
||||
VLLyricsNote(VLFraction dur=0, int pitch = kNoPitch);
|
||||
|
||||
std::vector<VLSyllable> fLyrics;
|
||||
};
|
||||
|
@ -250,6 +257,8 @@ struct VLMeasure {
|
|||
|
||||
bool IsEmpty() const;
|
||||
bool NoChords() const;
|
||||
|
||||
void DecomposeNotes(const VLProperties & prop, VLNoteList & decomposed) const;
|
||||
};
|
||||
|
||||
struct VLRepeat {
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void) drawNote:(VLFraction)dur at:(NSPoint)p
|
||||
- (void) drawNote:(int)visual at:(NSPoint)p
|
||||
accidental:(VLMusicElement)accidental tied:(BOOL)tied
|
||||
{
|
||||
NSPoint s = p;
|
||||
|
@ -147,11 +147,11 @@
|
|||
// Draw note head
|
||||
//
|
||||
NSImage * head;
|
||||
switch (dur.fDenom) {
|
||||
case 1:
|
||||
switch (visual & VLNote::kNoteHead) {
|
||||
case VLNote::kWhole:
|
||||
head = [self musicElement:kMusicWholeNote];
|
||||
break;
|
||||
case 2:
|
||||
case VLNote::kHalf:
|
||||
head = [self musicElement:kMusicHalfNote];
|
||||
s.x -= 1.0f;
|
||||
break;
|
||||
|
@ -190,19 +190,19 @@
|
|||
//
|
||||
//
|
||||
//
|
||||
if (dur.fDenom > 1) {
|
||||
if (visual > 0) {
|
||||
NSBezierPath * bz = [NSBezierPath bezierPath];
|
||||
NSPoint s1 = NSMakePoint(s.x, s.y+kStemH);
|
||||
NSImage * flag = nil;
|
||||
switch (dur.fDenom) {
|
||||
case 8:
|
||||
switch (visual) {
|
||||
case VLNote::kEighth:
|
||||
flag = [self musicElement:kMusicEighthFlag];
|
||||
break;
|
||||
case 16:
|
||||
case VLNote::k16th:
|
||||
flag = [self musicElement:kMusicSixteenthFlag];
|
||||
s1.y += 5.0f;
|
||||
break;
|
||||
case 32:
|
||||
case VLNote::k32nd:
|
||||
flag = [self musicElement:kMusicThirtysecondthFlag];
|
||||
s1.y += 13.0f;
|
||||
break;
|
||||
|
@ -239,34 +239,34 @@
|
|||
fLastNoteCenter = c;
|
||||
}
|
||||
|
||||
- (void) drawRest:(VLFraction)dur at:(NSPoint)p
|
||||
- (void) drawRest:(int)visual at:(NSPoint)p
|
||||
{
|
||||
//
|
||||
// Draw rest
|
||||
//
|
||||
NSImage * head = nil;
|
||||
switch (dur.fDenom) {
|
||||
case 1:
|
||||
switch (visual) {
|
||||
case VLNote::kWhole:
|
||||
head = [self musicElement:kMusicWholeRest];
|
||||
p.y += kWholeRestY;
|
||||
break;
|
||||
case 2:
|
||||
case VLNote::kHalf:
|
||||
head = [self musicElement:kMusicHalfRest];
|
||||
p.y += kHalfRestY;
|
||||
break;
|
||||
case 4:
|
||||
case VLNote::kQuarter:
|
||||
head = [self musicElement:kMusicQuarterRest];
|
||||
p.x -= kNoteX;
|
||||
break;
|
||||
case 8:
|
||||
case VLNote::kEighth:
|
||||
head = [self musicElement:kMusicEighthRest];
|
||||
p.x -= kNoteX;
|
||||
break;
|
||||
case 16:
|
||||
case VLNote::k16th:
|
||||
head = [self musicElement:kMusicSixteenthRest];
|
||||
p.x -= kNoteX;
|
||||
break;
|
||||
case 32:
|
||||
case VLNote::k32nd:
|
||||
head = [self musicElement:kMusicThirtysecondthRest];
|
||||
p.x -= kNoteX;
|
||||
break;
|
||||
|
@ -287,63 +287,48 @@
|
|||
int measIdx = m+system*fMeasPerSystem;
|
||||
if (measIdx >= song->CountMeasures())
|
||||
break;
|
||||
const VLMeasure measure = song->fMeasures[measIdx];
|
||||
const VLNoteList & melody = measure.fMelody;
|
||||
const VLMeasure & measure = song->fMeasures[measIdx];
|
||||
VLNoteList melody;
|
||||
measure.DecomposeNotes(song->fProperties[measure.fPropIdx], melody);
|
||||
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 & VLNote::kTiedWithPrev);
|
||||
int pitch = note->fPitch;
|
||||
while (dur > 0) {
|
||||
VLFraction partialDur; // Actual value of note drawn
|
||||
VLFraction noteDur; // Visual value of note
|
||||
prop.PartialNote(at, dur, dur==prevDur || dur==nextDur,
|
||||
&partialDur);
|
||||
prop.VisualNote(at, partialDur, triplet, ¬eDur, &triplet);
|
||||
prevDur = partialDur;
|
||||
if (pitch != VLNote::kNoPitch) {
|
||||
[self drawLedgerLinesWithPitch:pitch
|
||||
at:NSMakePoint([self noteXInMeasure:m at:at], kSystemY)];
|
||||
VLMusicElement accidental;
|
||||
NSPoint pos =
|
||||
NSMakePoint([self noteXInMeasure:m at:at],
|
||||
kSystemY+[self noteYWithPitch:pitch
|
||||
accidental:&accidental]);
|
||||
VLMusicElement acc = accidental;
|
||||
int step= [self stepWithPitch:pitch];
|
||||
if (acc == accidentals[step])
|
||||
acc = kMusicNothing; // Don't repeat accidentals
|
||||
else if (acc == kMusicNothing)
|
||||
if (accidentals[step] == kMusicNatural) // Resume signature
|
||||
acc = prop.fKey < 0 ? kMusicFlat : kMusicSharp;
|
||||
else
|
||||
acc = kMusicNatural;
|
||||
[self drawNote:noteDur
|
||||
at: pos
|
||||
accidental: acc
|
||||
tied:!first];
|
||||
accidentals[step] = accidental;
|
||||
} else {
|
||||
VLMusicElement accidental;
|
||||
NSPoint pos =
|
||||
NSMakePoint([self noteXInMeasure:m at:at],
|
||||
kSystemY+[self noteYWithPitch:65
|
||||
accidental:&accidental]);
|
||||
[self drawRest:noteDur at: pos];
|
||||
}
|
||||
dur -= partialDur;
|
||||
at += partialDur;
|
||||
first = NO;
|
||||
BOOL tied = (note != melody.begin() || m)
|
||||
&& note->fTied & VLNote::kTiedWithPrev;
|
||||
int pitch = note->fPitch;
|
||||
if (pitch != VLNote::kNoPitch) {
|
||||
[self drawLedgerLinesWithPitch:pitch
|
||||
at:NSMakePoint([self noteXInMeasure:m at:at], kSystemY)];
|
||||
VLMusicElement accidental;
|
||||
NSPoint pos =
|
||||
NSMakePoint([self noteXInMeasure:m at:at],
|
||||
kSystemY+[self noteYWithPitch:pitch
|
||||
accidental:&accidental]);
|
||||
VLMusicElement acc = accidental;
|
||||
int step= [self stepWithPitch:pitch];
|
||||
if (acc == accidentals[step])
|
||||
acc = kMusicNothing; // Don't repeat accidentals
|
||||
else if (acc == kMusicNothing)
|
||||
if (accidentals[step] == kMusicNatural) // Resume signature
|
||||
acc = prop.fKey < 0 ? kMusicFlat : kMusicSharp;
|
||||
else
|
||||
acc = kMusicNatural;
|
||||
[self drawNote:note->fVisual & VLNote::kNoteHead
|
||||
at: pos
|
||||
accidental: acc
|
||||
tied:tied];
|
||||
accidentals[step] = accidental;
|
||||
} else {
|
||||
VLMusicElement accidental;
|
||||
NSPoint pos =
|
||||
NSMakePoint([self noteXInMeasure:m at:at],
|
||||
kSystemY+[self noteYWithPitch:65
|
||||
accidental:&accidental]);
|
||||
[self drawRest:note->fVisual & VLNote::kNoteHead at: pos];
|
||||
}
|
||||
at += note->fDuration;
|
||||
}
|
||||
}
|
||||
if (fCursorPitch != VLNote::kNoPitch && fCursorMeasure/fMeasPerSystem == system)
|
||||
|
|
|
@ -38,7 +38,7 @@ std::ostream & operator<<(std::ostream & s, VLFraction f)
|
|||
s << whole;
|
||||
f -= whole;
|
||||
if (f.fNum)
|
||||
s << int(f.fNum) << '/' << int(f.fDenom);
|
||||
s << '.' << int(f.fNum) << '/' << int(f.fDenom);
|
||||
} else if (f.fNum) {
|
||||
s << int(f.fNum) << '/' << int(f.fDenom);
|
||||
} else {
|
||||
|
@ -65,50 +65,44 @@ void PrintName(const VLChord & chord)
|
|||
}
|
||||
}
|
||||
|
||||
template <class C> class Printer {
|
||||
VLProperties * fProp;
|
||||
VLFraction fAt;
|
||||
public:
|
||||
Printer(VLProperties * prop) : fProp(prop) {}
|
||||
|
||||
void operator()(const C& obj) {
|
||||
PrintName(obj);
|
||||
|
||||
std::cout << '@';
|
||||
for (VLFraction d = obj.fDuration; d > 0; ) {
|
||||
VLFraction p;
|
||||
fProp->PartialNote(fAt, d, &p);
|
||||
if (d < obj.fDuration)
|
||||
std::cout << '+';
|
||||
std::cout << p;
|
||||
d -= p;
|
||||
fAt += p;
|
||||
}
|
||||
std::cout << ' ';
|
||||
}
|
||||
};
|
||||
|
||||
void PrintMeasure(const VLMeasure & measure)
|
||||
void ChordPrinter(const VLChord & chord)
|
||||
{
|
||||
std::for_each(measure.fChords.begin(), measure.fChords.end(),
|
||||
Printer<VLChord>(measure.fProperties));
|
||||
PrintName(chord);
|
||||
if (chord.fDuration != VLFraction(1,4))
|
||||
std::cout << " * " << chord.fDuration;
|
||||
std::cout << ' ';
|
||||
}
|
||||
|
||||
void NotePrinter(const VLLyricsNote & note)
|
||||
{
|
||||
if (note.fTied & VLNote::kTiedWithPrev)
|
||||
std::cout << "~ ";
|
||||
PrintName(note);
|
||||
std::cout << ' ' << note.fDuration
|
||||
<< '[' << ((note.fVisual & VLNote::kTriplet) ? "T" : "")
|
||||
<< (note.fVisual & VLNote::kNoteHead)["124863"] << "] ";
|
||||
}
|
||||
|
||||
void PrintMeasure(const VLMeasure & measure, const VLProperties & prop)
|
||||
{
|
||||
std::for_each(measure.fChords.begin(), measure.fChords.end(), ChordPrinter);
|
||||
std::cout << std::endl;
|
||||
std::for_each(measure.fMelody.begin(), measure.fMelody.end(),
|
||||
Printer<VLNote>(measure.fProperties));
|
||||
VLNoteList decomposed;
|
||||
measure.DecomposeNotes(prop, decomposed);
|
||||
std::for_each(decomposed.begin(), decomposed.end(), NotePrinter);
|
||||
std::cout << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void PrintSong(const VLSong & song)
|
||||
{
|
||||
std::for_each(song.fMeasures.begin(), song.fMeasures.end(), PrintMeasure);
|
||||
for (size_t i=0; i<song.CountMeasures()-song.EmptyEnding(); ++i)
|
||||
PrintMeasure(song.fMeasures[i], song.fProperties[song.fMeasures[i].fPropIdx]);
|
||||
}
|
||||
|
||||
int main(int, char *const [])
|
||||
{
|
||||
VLSong song;
|
||||
|
||||
song.fMeasures.resize(4);
|
||||
|
||||
char command;
|
||||
while (std::cin >> command) {
|
||||
int measure;
|
||||
|
@ -117,7 +111,7 @@ int main(int, char *const [])
|
|||
switch (command) {
|
||||
case '+':
|
||||
std::cin >> name >> measure >> at;
|
||||
song.AddNote(name, measure, at);
|
||||
song.AddNote(VLNote(name), measure, at);
|
||||
|
||||
PrintSong(song);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user