Revamp tuplet model

This commit is contained in:
Matthias Neeracher 2011-08-31 04:02:37 +02:00
parent 424a40bd07
commit 9d198f5cec
6 changed files with 65 additions and 41 deletions

View File

@ -261,9 +261,10 @@ void VLLilypondWriter::VisitNote(VLLyricsNote & n)
&& n.fPitch == fPrevNote.fPitch
)
strcpy(duration, ".");
else if (n.fVisual & VLNote::kTriplet)
sprintf(duration, "%s\\times 2/3 { %s%d%s }",
space, nm.c_str(), kValue[n.fVisual & VLNote::kNoteHeadMask], tie);
else if (n.fVisual & VLNote::kTupletMask)
sprintf(duration, "%s\\times %d/%d { %s%d%s }",
space, VLNote::TupletDenom(n.fVisual), VLNote::TupletNum(n.fVisual),
nm.c_str(), kValue[n.fVisual & VLNote::kNoteHeadMask], tie);
else
sprintf(duration, "%s%s%d%s",
space, nm.c_str(), kValue[n.fVisual & VLNote::kNoteHeadMask], tie);

View File

@ -314,7 +314,7 @@ void VLMeasure::DecomposeNotes(const VLProperties & prop, VLNoteList & decompose
p.AlignToGrid(inBeat, kQuarterDur); // Align all others
}
checkTriplets:
if (p.fVisual & VLNote::kTriplet) {
if ((p.fVisual & VLNote::kTupletMask) == VLNote::kTriplet) {
//
// Distinguish swing 8ths/16ths from triplets
//
@ -335,7 +335,7 @@ void VLMeasure::DecomposeNotes(const VLProperties & prop, VLNoteList & decompose
//
// First swing note (4th triplet -> 8th)
//
p.fVisual = (p.fVisual+1) & ~VLNote::kTriplet;
p.fVisual = (p.fVisual+1) & ~VLNote::kTupletMask;
}
} else if ((p.fDuration == sw12 && ((at+p.fDuration) % grid4 == 0))
|| (swing16 && p.fDuration == sw24 && ((at+p.fDuration) % grid8 == 0))
@ -344,7 +344,7 @@ void VLMeasure::DecomposeNotes(const VLProperties & prop, VLNoteList & decompose
// Second swing note (8th triplet -> 8th)
//
if (!prevTriplets)
p.fVisual &= ~VLNote::kTriplet;
p.fVisual &= ~VLNote::kTupletMask;
} else if ((p.fDuration > kMinDuration) &&
((at % p.fDuration != 0)
|| (p.fDuration != c.fDuration
@ -357,11 +357,11 @@ void VLMeasure::DecomposeNotes(const VLProperties & prop, VLNoteList & decompose
// Get rid of awkward triplets
//
p.fDuration *= VLFraction(3,4);
p.fVisual = (p.fVisual+1) & ~VLNote::kTriplet;
p.fVisual = (p.fVisual+1) & ~VLNote::kTupletMask;
}
}
haveDuration:
if (p.fVisual & VLNote::kTriplet)
if ((p.fVisual & VLNote::kTupletMask) == VLNote::kTriplet)
if ((prevTriplets = (prevTriplets+1)%3)) {
prevTripDur = p.fDuration;
prevVisual = p.fVisual;
@ -554,8 +554,7 @@ void VLSong::AddNote(VLLyricsNote note, size_t measure, VLFraction at)
//
// Sanity check on accidentals
//
note.fVisual = (note.fVisual & ~VLNote::kAccidentalsMask)
| VLPitchAccidental(note.fPitch, note.fVisual, Properties(measure).fKey);
note.fVisual = VLPitchAccidental(note.fPitch, note.fVisual, Properties(measure).fKey);
//
// Always keep an empty measure in reserve
//
@ -2080,6 +2079,9 @@ std::string VLSong::PrimaryGroove() const
return bestGroove;
}
#pragma mark -
#pragma mark class VLSongVisitor
//////////////////////// VLSongVisitor ////////////////////////////////
VLSongVisitor::~VLSongVisitor()

View File

@ -132,20 +132,22 @@ struct VLNote {
kWantSharp = 0x10,
kWant2Sharp = 0x20,
kPreferSharps = 0x30, // kWantSharp | kWant2Sharp
kPreferSharps = 0x30, // kWantSharp | kWant2Sharp
kWantFlat = 0x40,
kWant2Flat = 0x80,
kPreferFlats = 0xC0, // kWantFlat | kWant2Flat
kWantNatural = 0x50, // kWantSharp | kWantFlat
kNaturalOrSharp = 0x70, // kPreferSharps| kWantFlat
kNaturalOrFlat = 0xD0, // kPreferFlats | kWantSharp
kPreferFlats = 0xC0, // kWantFlat | kWant2Flat
kWantNatural = 0x50, // kWantSharp | kWantFlat
kNaturalOrSharp = 0x70, // kPreferSharps| kWantFlat
kNaturalOrFlat = 0xD0, // kPreferFlats | kWantSharp
kAccidentalsMask= 0x00F0,
kTriplet = 0x300,
kTriplet = 0x3200,
kTupletMask = 0x0F00
kTupletMask = 0xFF00
};
static int TupletNum(uint16_t visual) { return visual >> 12; }
static int TupletDenom(uint16_t visual) { return (visual >> 8) & 0x0F; }
VLNote(VLFraction dur=0, int pitch=kNoPitch, uint16_t visual=0);
VLNote(std::string name);
std::string Name(uint16_t accidentals=0) const;

View File

@ -542,6 +542,8 @@ advanceAt:
[filterTask release];
if ([error length]) {
[contents writeToFile:@"/var/tmp/VocalEaselFilterInput" atomically:NO];
[error writeToFile:@"/var/tmp/VocalEaselFilterError" atomically:NO];
NSString * errStr = [[[NSString alloc] initWithData:error
encoding:NSUTF8StringEncoding] autorelease];
[NSException raise:NSInvalidArgumentException

View File

@ -10,7 +10,7 @@
const float kLineX = 5.0;
const float kLineH = 10.0;
const float kTripletH = 5.0;
const float kTupletH = 5.0;
#define kSystemBaseline ((fNumBotLedgers+1)*kLineH+fNumStanzas*kLyricsH)
#define kSystemAscent ((fNumTopLedgers+7)*kLineH+kChordH)
#define kSystemH (kSystemBaseline+kSystemAscent)

View File

@ -296,7 +296,7 @@
operation: NSCompositeSourceOver];
}
- (void) drawTripletBracketFrom:(int)startX to:(int)endX atY:(int)y
- (void) drawTuplet:(uint16_t)tuplet bracketFrom:(int)startX to:(int)endX atY:(int)y
{
static NSDictionary * sTripletFont = nil;
if (!sTripletFont)
@ -308,13 +308,15 @@
NSBezierPath * bz = [NSBezierPath bezierPath];
[bz moveToPoint: NSMakePoint(startX, y-kTripletH)];
[bz moveToPoint: NSMakePoint(startX, y-kTupletH)];
[bz lineToPoint: NSMakePoint(startX, y)];
[bz lineToPoint: NSMakePoint(endX, y)];
[bz lineToPoint: NSMakePoint(endX, y-kTripletH)];
[bz lineToPoint: NSMakePoint(endX, y-kTupletH)];
[bz stroke];
[@"3" drawAtPoint: NSMakePoint((startX+endX)*0.5f, y+kTripletH)
NSString * tupletText = tuplet == VLNote::kTriplet ? @"3"
: [NSString stringWithFormat:@"%d:%d", VLNote::TupletNum(tuplet), VLNote::TupletDenom(tuplet)];
[tupletText drawAtPoint: NSMakePoint((startX+endX)*0.5f, y+kTupletH)
withAttributes: sTripletFont];
}
@ -326,11 +328,6 @@
const VLSystemLayout & kLayout = (*fLayout)[system];
const CGFloat kSystemY = [self systemY:system];
float tripletStartX;
float tripletEndX;
CGFloat tripletY;
bool hasTriplets = false;
for (int m = 0; m<kLayout.NumMeasures(); ++m) {
VLVisualFilter filterVisuals(kProp.fKey);
int measIdx = m+kFirstMeas;
@ -340,6 +337,13 @@
VLNoteList melody;
measure.DecomposeNotes(kProp, melody);
VLFraction at(0);
float tupletStartX;
float tupletEndX;
CGFloat tupletY;
int inTuplet = 0;
uint16_t tuplet;
VLFraction tupletDur;
for (VLNoteList::const_iterator note = melody.begin();
note != melody.end();
++note
@ -369,25 +373,38 @@
kSystemY+[self noteYInSection:measure.fPropIdx withPitch:65]);
[self drawRest:note->fVisual & VLNote::kNoteHeadMask at: pos];
}
if (note->fVisual & VLNote::kTriplet) {
tripletEndX = pos.x+kNoteW*0.5f;
if (hasTriplets) {
tripletY = std::max(tripletY, pos.y+kLineH);
} else {
tripletY = std::max(kSystemY+5.0f*kLineH, pos.y+kLineH);
tripletStartX = pos.x-kNoteW*0.5f;
hasTriplets = true;
if (uint16_t newTuplet = note->fVisual & VLNote::kTupletMask) {
tupletEndX = pos.x+kNoteW*0.5f;
if (inTuplet && newTuplet == tuplet) {
tupletY = std::max(tupletY, pos.y+kLineH);
} else {
if (inTuplet)
[self drawTuplet:tuplet bracketFrom:tupletStartX to:tupletEndX atY:tupletY];
tupletY = std::max(kSystemY+5.0f*kLineH, pos.y+kLineH);
tupletStartX = pos.x-kNoteW*0.5f;
tuplet = newTuplet;
tupletDur = 0;
}
} else if (hasTriplets) {
[self drawTripletBracketFrom:tripletStartX to:tripletEndX atY:tripletY];
hasTriplets = false;
++inTuplet;
tupletDur += note->fDuration / VLNote::TupletDenom(tuplet);
if (tuplet == VLNote::kTriplet ? (tupletDur.fNum == 1 && !(tupletDur.fDenom & (tupletDur.fDenom-1)))
: inTuplet == VLNote::TupletNum(tuplet)
) {
//
// Tuplet adds up to power of two fraction
//
[self drawTuplet:tuplet bracketFrom:tupletStartX to:tupletEndX atY:tupletY];
inTuplet = 0;
}
} else if (++inTuplet) {
[self drawTuplet:tuplet bracketFrom:tupletStartX to:tupletEndX atY:tupletY];
inTuplet = 0;
}
at += note->fDuration;
}
}
if (hasTriplets) {
[self drawTripletBracketFrom:tripletStartX to:tripletEndX atY:tripletY];
if (inTuplet)
[self drawTuplet:tuplet bracketFrom:tupletStartX to:tupletEndX atY:tupletY];
}
if (fCursorRegion == kRegionNote && fLayout->SystemForMeasure(fCursorMeasure) == system)
[self drawNoteCursor];