Draw by system, reorganize event handling

This commit is contained in:
Matthias Neeracher 2006-10-02 08:32:25 +00:00
parent 810ff2ee2f
commit 74a6637574
10 changed files with 491 additions and 413 deletions

View File

@ -31,6 +31,11 @@ private:
VLFraction & Normalize();
};
inline float operator*(VLFraction f, float sc)
{
return sc*f.fNum/f.fDenom;
}
inline VLFraction operator+(VLFraction one, VLFraction other)
{
return one += other;

View File

@ -33,25 +33,29 @@ enum VLMusicElement {
kMusicElements
};
enum VLRegion {
kRegionNowhere,
kRegionNote,
kRegionChord,
kRegionLyrics
};
@interface VLSheetView : NSView {
BOOL fNeedsRecalc;
BOOL fIsRest;
float fClefKeyW;
float fMeasureW;
float fLineH;
int fGroups;
int fQuarterBeats;
int fDivPerGroup;
int fMeasPerSystem;
int fNumSystems;
float fDisplayScale;
NSImageRep * fNoteCursorCache;
NSPoint fNoteCursorLocation;
NSPoint fLastNoteCenter;
NSRect fNoteRect;
NSTrackingRectTag fNoteRectTracker;
int fNoteCursorMeasure;
VLFract fNoteCursorAt;
int fNoteCursorPitch;
NSTrackingRectTag fCursorTracking;
int fCursorMeasure;
VLFract fCursorAt;
int fCursorPitch;
id fFieldBeingEdited;
BOOL fShowFieldEditor;
@ -71,8 +75,14 @@ enum VLMusicElement {
- (float) systemY:(int)system;
- (float) noteYWithPitch:(int)pitch;
- (float) noteYInMeasure:(int)measure withPitch:(int)pitch;
- (float) noteXInMeasure:(int)measure at:(VLFraction)at;
- (void) mouseMoved:(NSEvent *)event;
- (void) mouseDown:(NSEvent *)event;
- (void) mouseEntered:(NSEvent *)event;
- (void) mouseExited:(NSEvent *)event;
@end
// Local Variables:

View File

@ -10,6 +10,7 @@
#import "VLSheetViewInternal.h"
#import "VLSheetViewChords.h"
#import "VLSheetViewNotes.h"
#import "VLSoundOut.h"
#import "VLDocument.h"
@ -79,11 +80,10 @@ static float sFlatPos[] = {
}
}
fNeedsRecalc = YES;
fIsRest = NO;
fShowFieldEditor = NO;
fDisplayScale = 1.0f;
fNoteRectTracker = 0;
fNoteCursorCache = nil;
fNoteCursorMeasure = -1;
fCursorPitch = VLNote::kNoPitch;
}
return self;
}
@ -148,6 +148,11 @@ static float sFlatPos[] = {
}
}
- (float) noteYInMeasure:(int)measure withPitch:(int)pitch
{
return [self systemY:measure/fMeasPerSystem]+[self noteYWithPitch:pitch];
}
- (float) noteXInMeasure:(int)measure at:(VLFraction)at
{
const VLProperties & prop = [self song]->fProperties.front();
@ -161,11 +166,12 @@ static float sFlatPos[] = {
- (void) recalculateDimensions
{
NSScrollView * scroll = [self enclosingScrollView];
fNeedsRecalc = NO;
NSSize sz = [[self enclosingScrollView] contentSize];
sz.width /= fDisplayScale;
sz.height/= fDisplayScale;
NSSize sz = [scroll contentSize];
sz.width /= fDisplayScale;
sz.height /= fDisplayScale;
const VLSong * song = [self song];
const VLProperties & prop = song->fProperties.front();
@ -179,21 +185,16 @@ static float sFlatPos[] = {
fNumSystems = (song->CountMeasures()+fMeasPerSystem-1)/fMeasPerSystem;
sz.height = fNumSystems*kSystemH;
#if 0
noteRect = NSMakeRect(clefKeyW, kLineY-kMaxLedgers*kLineH,
visibleMeasures*fMeasureW,
(4.0f+2.0f*kMaxLedgers)*kLineH);
NSRect r = [scroll bounds];
NSPoint mouse =
[self convertPoint:[[self window] mouseLocationOutsideOfEventStream]
[scroll convertPoint:[[self window] mouseLocationOutsideOfEventStream]
fromView: nil];
BOOL inNoteRect = [self mouse:mouse inRect:noteRect];
BOOL within = [scroll mouse:mouse inRect:r];
[self removeTrackingRect:noteRectTracker];
noteRectTracker = [self addTrackingRect:noteRect owner:self
userData:nil assumeInside:inNoteRect];
[[self window] setAcceptsMouseMovedEvents:inNoteRect];
#endif
[self removeTrackingRect:fCursorTracking];
fCursorTracking = [self addTrackingRect:r owner:self
userData:nil assumeInside:within];
[[self window] setAcceptsMouseMovedEvents:within];
[[self window] makeFirstResponder:self];
NSSize frameSz = {sz.width * fDisplayScale, sz.height * fDisplayScale};
@ -203,7 +204,7 @@ static float sFlatPos[] = {
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)rect
- (void)drawGridForSystem:(int)system
{
static NSDictionary * sMeasNoFont = nil;
if (!sMeasNoFont)
@ -213,6 +214,9 @@ static float sFlatPos[] = {
NSFontAttributeName,
nil];
const float kSystemY = [self systemY:system];
const float kLineW = fClefKeyW + fMeasPerSystem*fMeasureW;
const VLSong * song = [self song];
const VLProperties & prop = song->fProperties.front();
@ -222,17 +226,10 @@ static float sFlatPos[] = {
// Draw lines
//
[bz setLineWidth:0.0];
if (fNeedsRecalc)
[self recalculateDimensions];
for (int system = 0; system<fNumSystems; ++system) {
float kLineY = [self systemY:system];
for (int line = 0; line<5; ++line) {
const float x0 = kLineX;
const float xx = x0 + fClefKeyW + fMeasPerSystem*fMeasureW;
const float y = kLineY+line*kLineH;
[bz moveToPoint: NSMakePoint(x0, y)];
[bz lineToPoint: NSMakePoint(xx, y)];
}
for (int line = 0; line<5; ++line) {
const float y = kSystemY+line*kLineH;
[bz moveToPoint: NSMakePoint(kLineX, y)];
[bz lineToPoint: NSMakePoint(kLineX+kLineW, y)];
}
[bz stroke];
[bz removeAllPoints];
@ -240,14 +237,11 @@ static float sFlatPos[] = {
// Draw measure lines
//
[bz setLineWidth:2.0];
for (int system = 0; system<fNumSystems; ++system) {
float kLineY = [self systemY:system];
for (int measure = 0; measure<=fMeasPerSystem; ++measure) {
const float x = fClefKeyW+measure*fMeasureW;
const float yy = kLineY+4.0f*kLineH;
[bz moveToPoint: NSMakePoint(x, kLineY)];
[bz lineToPoint: NSMakePoint(x, yy)];
}
for (int measure = 0; measure<=fMeasPerSystem; ++measure) {
const float x = fClefKeyW+measure*fMeasureW;
const float yy = kSystemY+4.0f*kLineH;
[bz moveToPoint: NSMakePoint(x, kSystemY)];
[bz lineToPoint: NSMakePoint(x, yy)];
}
[bz stroke];
[bz removeAllPoints];
@ -257,63 +251,73 @@ static float sFlatPos[] = {
//
[bz setLineWidth:0.0];
[[NSColor colorWithDeviceWhite:0.8f alpha:1.0f] set];
for (int system = 0; system<fNumSystems; ++system) {
float kLineY = [self systemY:system];
for (int measure = 0; measure<fMeasPerSystem; ++measure) {
const float mx = fClefKeyW+measure*fMeasureW;
const float y0 = kLineY-2.0f*kLineH;
const float yy = kLineY+6.0f*kLineH;
for (int group = 0; group < fGroups; ++group) {
for (int div = 0; div < fDivPerGroup; ++div) {
const float x = mx+(group*(fDivPerGroup+1)+div+1)*kNoteW;
[bz moveToPoint: NSMakePoint(x, y0)];
[bz lineToPoint: NSMakePoint(x, yy)];
}
}
}
}
[bz stroke];
for (int system = 0; system<fNumSystems; ++system) {
float kLineY = [self systemY:system];
//
// Draw clef
//
[[self musicElement:kMusicGClef]
compositeToPoint: NSMakePoint(kClefX, kLineY+kClefY)
operation: NSCompositeSourceOver];
//
// Draw measure #
//
[[NSString stringWithFormat:@"%d", system*fMeasPerSystem+1]
drawAtPoint: NSMakePoint(kMeasNoX, kLineY+kMeasNoY)
withAttributes: sMeasNoFont];
//
// Draw key (sharps & flats)
//
if (prop.fKey > 0) {
float x = kClefX+kClefW;
for (int i=0; i<prop.fKey; ++i) {
[[self musicElement:kMusicSharp]
compositeToPoint: NSMakePoint(x, kLineY+sSharpPos[i]+kSharpY)
operation: NSCompositeSourceOver];
x += kAccW;
}
} else if (prop.fKey < 0) {
float x = kClefX+kClefW;
for (int i=0; -i>prop.fKey; ++i) {
[[self musicElement: kMusicFlat]
compositeToPoint: NSMakePoint(x, kLineY+sFlatPos[i]+kFlatY)
operation: NSCompositeSourceOver];
x += kAccW;
for (int measure = 0; measure<fMeasPerSystem; ++measure) {
const float mx = fClefKeyW+measure*fMeasureW;
const float y0 = kSystemY-2.0f*kLineH;
const float yy = kSystemY+6.0f*kLineH;
for (int group = 0; group < fGroups; ++group) {
for (int div = 0; div < fDivPerGroup; ++div) {
const float x = mx+(group*(fDivPerGroup+1)+div+1)*kNoteW;
[bz moveToPoint: NSMakePoint(x, y0)];
[bz lineToPoint: NSMakePoint(x, yy)];
}
}
}
[bz stroke];
//
// Draw notes
// Draw clef
//
[self drawNotes];
[[self musicElement:kMusicGClef]
compositeToPoint: NSMakePoint(kClefX, kSystemY+kClefY)
operation: NSCompositeSourceOver];
//
// Draw measure #
//
[[NSString stringWithFormat:@"%d", system*fMeasPerSystem+1]
drawAtPoint: NSMakePoint(kMeasNoX, kSystemY+kMeasNoY)
withAttributes: sMeasNoFont];
//
// Draw key (sharps & flats)
//
if (prop.fKey > 0) {
float x = kClefX+kClefW;
for (int i=0; i<prop.fKey; ++i) {
[[self musicElement:kMusicSharp]
compositeToPoint:
NSMakePoint(x, kSystemY+sSharpPos[i]+kSharpY)
operation: NSCompositeSourceOver];
x += kAccW;
}
} else if (prop.fKey < 0) {
float x = kClefX+kClefW;
for (int i=0; -i>prop.fKey; ++i) {
[[self musicElement: kMusicFlat]
compositeToPoint:
NSMakePoint(x, kSystemY+sFlatPos[i]+kFlatY)
operation: NSCompositeSourceOver];
x += kAccW;
}
}
}
- (void)drawRect:(NSRect)rect
{
if (fNeedsRecalc)
[self recalculateDimensions];
const float kLineW = fClefKeyW + fMeasPerSystem*fMeasureW;
for (int system = 0; system<fNumSystems; ++system) {
const float kSystemY = [self systemY:system];
if (!NSIntersectsRect(rect,
NSMakeRect(kLineX, kSystemY+kClefY,
kLineW, kSystemH-kClefY)
))
continue; // This system does not need to be drawn
[self drawGridForSystem:system];
[self drawNotesForSystem:system];
[self drawChordsForSystem:system];
}
}
- (IBAction) setKey:(id)sender
@ -358,4 +362,112 @@ static float sFlatPos[] = {
forKey: @"fShowFieldEditor"];
}
const float kSemiFloor = -2.5f*kLineH;
static int sSemiToPitch[] = {
53, // F
55, 57, // A
59, 60, // Middle C
62, 64, // E
65, 67, // G
69, 71, // B
72, 74, // D
76, 77, // F
79, 81, // A
83, 84, // C
86, 88 // E
};
- (VLRegion) findRegionForEvent:(NSEvent *) event
{
fCursorPitch = VLNote::kNoPitch;
const VLProperties & prop = [self song]->fProperties.front();
NSPoint loc = [event locationInWindow];
loc = [self convertPoint:loc fromView:nil];
if (loc.y < 0.0f || loc.y >= fNumSystems*kSystemH)
return kRegionNowhere;
int system = fNumSystems - static_cast<int>(loc.y / kSystemH) - 1;
loc.y = fmodf(loc.y, kSystemH);
loc.x -= fClefKeyW;
if (loc.x < 0.0f || loc.x >= fMeasPerSystem*fMeasureW)
return kRegionNowhere;
int measure = static_cast<int>(loc.x / fMeasureW);
loc.x -= measure*fMeasureW;
int group = static_cast<int>(loc.x / ((fDivPerGroup+1)*kNoteW));
loc.x -= group*(fDivPerGroup+1)*kNoteW;
int div = static_cast<int>(roundf(loc.x / kNoteW))-1;
div = std::min(std::max(div, 0), fDivPerGroup-1);
fCursorAt = VLFraction(div+group*fDivPerGroup, 4*prop.fDivisions);
fCursorMeasure = measure+system*fMeasPerSystem;
if (loc.y >= kSystemY+kChordY)
return kRegionChord;
else if (loc.y < kSystemY+kLyricsY)
return kRegionLyrics;
loc.y -= kSystemY+kSemiFloor;
int semi = static_cast<int>(roundf(loc.y / (0.5f*kLineH)));
fCursorPitch = sSemiToPitch[semi];
return kRegionNote;
}
- (void) mouseMoved:(NSEvent *)event
{
if ([event modifierFlags] & NSAlphaShiftKeyMask)
return; // Keyboard mode, ignore mouse
bool hadCursor = fCursorPitch != VLNote::kNoPitch;
[self findRegionForEvent:event];
bool hasCursor = fCursorPitch != VLNote::kNoPitch;
[self setNeedsDisplay:(hadCursor || hasCursor)];
}
- (void) mouseEntered:(NSEvent *)event
{
[[self window] setAcceptsMouseMovedEvents:YES];
[self mouseMoved:event];
}
- (void) mouseExited:(NSEvent *)event
{
[[self window] setAcceptsMouseMovedEvents:NO];
[self mouseMoved:event];
}
- (void) mouseDown:(NSEvent *)event
{
switch ([self findRegionForEvent:event]) {
case kRegionNote:
[self addNoteAtCursor];
break;
default:
break;
}
}
- (void) keyDown:(NSEvent *)event
{
NSString * k = [event charactersIgnoringModifiers];
switch ([k characterAtIndex:0]) {
case '\r':
[self startKeyboardCursor];
[self addNoteAtCursor];
break;
case ' ':
[self startKeyboardCursor];
VLSoundOut::Instance()->PlayNote(VLNote(1, fCursorPitch));
break;
case 'r':
fIsRest = !fIsRest;
break;
}
}
@end

View File

@ -11,6 +11,10 @@
- (IBAction) editChord:(id)sender;
- (IBAction) doneEditingChord:(id)sender;
- (void) setupChords;
- (void) drawChordsForSystem:(int)system;
@end
// Local Variables:
// mode:ObjC
// End:

View File

@ -66,52 +66,31 @@
return s;
}
- (void) setupChords
- (void) drawChordsForSystem:(int)system
{
#if 0
const VLSong * song = [self song];
const VLProperties & prop = song->fProperties.front();
NSView * chordView = [chords contentView];
//
// Delete old list of chord boxes
//
for (NSEnumerator * e = [[chordView subviews] objectEnumerator];
NSView * subview = [e nextObject];
)
[subview removeFromSuperview];
//
// Build new list
//
NSFont * chordFont = [NSFont controlContentFontOfSize: 14];
int beatsPerGroup = quarterBeats / groups;
for (int m = 0; m<visibleMeasures; ++m) {
const float x0 = clefKeyW+m*measureW;
int measure = firstMeasure+m;
VLChordList::const_iterator cCur = song->fMeasures[measure].fChords.begin();
VLChordList::const_iterator cEnd = song->fMeasures[measure].fChords.end();
VLFraction at(0);
for (int beat = 0; beat<quarterBeats; ++beat) {
const float x = x0+kNoteW*(beat*prop.fDivisions+(beat / beatsPerGroup)+0.5f);
NSRect f = NSMakeRect(x, 0, kChordW, kChordH);
NSButton * chord = [[NSButton alloc] initWithFrame: f];
[chordView addSubview: chord];
[chord setBordered: NO];
[chord setTarget: self];
[chord setAction: @selector(editChord:)];
[chord setTag: (measure << 8) | beat];
[chord setFont: chordFont];
[chord setTitle: @""];
while (cCur != cEnd && at < VLFraction(beat, 4))
at += (cCur++)->fDuration;
if (cCur != cEnd && at == VLFraction(beat, 4) && cCur->fPitch != VLNote::kNoPitch)
[chord setTitle: [self stringWithChord:*cCur]];
[chord release];
for (int m = 0; m<fMeasPerSystem; ++m) {
int measIdx = m+system*fMeasPerSystem;
if (measIdx >= song->CountMeasures())
break;
const VLMeasure measure = song->fMeasures[measIdx];
const VLChordList & chords = measure.fChords;
VLFraction at(0);
for (VLChordList::const_iterator chord = chords.begin();
chord != chords.end();
++chord
) {
NSAttributedString * chordName = [self stringWithChord:*chord];
NSPoint chordLoc =
NSMakePoint(kClefX+kClefW+(m+at)*fMeasureW+0.5f*kNoteW,
kSystemY+kChordY);
[chordName drawAtPoint:chordLoc];
}
}
[chords setNeedsDisplay: YES];
#endif
}
- (IBAction) editChord:(id)sender

View File

@ -6,8 +6,8 @@
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
const float kLineX = 5;
const float kLineH = 10;
const float kLineX = 5.0;
const float kLineH = 10.0;
const float kSystemH = 15.0f*kLineH;
const float kSystemY = 3.0f*kLineH;
const float kClefX = 20.5f;
@ -21,8 +21,10 @@ const float kAccW = 10.0f;
const float kSharpY =-15.0f;
const float kFlatY = -7.0f;
const float kImgScale = 0.04f;
const float kChordY = 7.0f*kLineH;
const float kChordW = 40.0f;
const float kChordH = 25.0f;
const float kLyricsY = -3.0*kLineH;
const float kNoteX = 7.0f;
const float kNoteY = 5.0f;
const float kStemX = 0.0f;

View File

@ -10,14 +10,11 @@
@interface VLSheetView (Notes)
- (void) mouseMoved:(NSEvent *)event;
- (void) mouseDown:(NSEvent *)event;
- (void) mouseEntered:(NSEvent *)event;
- (void) mouseExited:(NSEvent *)event;
- (void) drawNotes;
- (void) setNoteCursorMeasure:(int)measure at:(VLFraction)at pitch:(int)pitch;
- (void) hideNoteCursor;
- (void) drawNotesForSystem:(int)system;
- (void) addNoteAtCursor;
@end
// Local Variables:
// mode:ObjC
// End:

View File

@ -15,112 +15,35 @@
@implementation VLSheetView (Notes)
static int sSemiToPitch[] = {
53, // F
55, 57, // A
59, 60, // Middle C
62, 64, // E
65, 67, // G
69, 71, // B
72, 74, // D
76, 77, // F
79, 81, // A
83, 84, // C
86, 88 // E
};
- (void) mouseMoved:(NSEvent *)event
{
if ([event modifierFlags] & NSAlphaShiftKeyMask)
return; // Keyboard mode, ignore mouse
const VLProperties & prop = [self song]->fProperties.front();
NSPoint loc = [event locationInWindow];
loc = [self convertPoint:loc fromView:nil];
loc.x -= fNoteRect.origin.x;
int measure = static_cast<int>(loc.x / fMeasureW);
loc.x -= measure*fMeasureW;
int group = static_cast<int>(loc.x / ((fDivPerGroup+1)*kNoteW));
loc.x -= group*(fDivPerGroup+1)*kNoteW;
int div = static_cast<int>(roundf(loc.x / kNoteW))-1;
div = std::min(std::max(div, 0), fDivPerGroup-1);
VLFraction at(div+group*fDivPerGroup, 4*prop.fDivisions);
loc.y -= fNoteRect.origin.y;
int semi = static_cast<int>(roundf(loc.y / (0.5f*kLineH)));
int pitch = sSemiToPitch[semi];
[self setNoteCursorMeasure:measure at:at pitch:pitch];
}
- (void) addNoteAtCursor:(BOOL)isRest
- (void) addNoteAtCursor
{
if (fNoteCursorMeasure > -1) {
VLNote newNote(1, !isRest ? fNoteCursorPitch : VLNote::kNoPitch);
if (fCursorMeasure > -1) {
VLNote newNote(1, !fIsRest ? fCursorPitch : VLNote::kNoPitch);
[self song]->AddNote(newNote, fNoteCursorMeasure, fNoteCursorAt);
[self song]->AddNote(newNote, fCursorMeasure, fCursorAt);
[self setNeedsDisplay:YES];
VLSoundOut::Instance()->PlayNote(newNote);
fIsRest = NO;
}
}
- (void) mouseDown:(NSEvent *)event
{
[self mouseMoved:event];
[self addNoteAtCursor: ([event modifierFlags] & NSShiftKeyMask) != 0];
}
- (void) mouseEntered:(NSEvent *)event
{
[[self window] setAcceptsMouseMovedEvents:YES];
[self mouseMoved:event];
}
- (void) mouseExited:(NSEvent *)event
{
[[self window] setAcceptsMouseMovedEvents:NO];
if (!([event modifierFlags] & NSAlphaShiftKeyMask))
[self hideNoteCursor];
}
- (void) startKeyboardCursor
{
if (fNoteCursorMeasure < 0) {
fNoteCursorMeasure = 0;
fNoteCursorPitch = VLNote::kMiddleC;
fNoteCursorAt = VLFraction(0);
if (fCursorMeasure < 0) {
fCursorMeasure = 0;
fCursorPitch = VLNote::kMiddleC;
fCursorAt = VLFraction(0);
}
}
- (void) keyDown:(NSEvent *)event
{
NSString * k = [event charactersIgnoringModifiers];
switch ([k characterAtIndex:0]) {
case '\r':
[self startKeyboardCursor];
[self addNoteAtCursor];
break;
case ' ':
[self startKeyboardCursor];
VLSoundOut::Instance()->PlayNote(VLNote(1, fNoteCursorPitch));
break;
}
}
- (void) hideNoteCursor
{
fNoteCursorMeasure = -1;
[self setNeedsDisplay:YES];
}
- (void) drawNoteCursor
{
NSPoint note =
NSMakePoint([self noteXInMeasure:fNoteCursorMeasure at:fNoteCursorAt],
[self noteYWithPitch:fNoteCursorPitch]);
NSMakePoint([self noteXInMeasure:fCursorMeasure at:fCursorAt],
[self noteYInMeasure:fCursorMeasure withPitch:fCursorPitch]);
NSRect noteCursorRect =
NSMakeRect(note.x-kNoteX, note.y-kNoteY, 2.0f*kNoteX, 2.0f*kNoteY);
[[self musicElement:kMusicNoteCursor]
@ -245,7 +168,7 @@ static int sSemiToPitch[] = {
operation: NSCompositeSourceOver];
}
- (void) drawNotes
- (void) drawNotesForSystem:(int)system
{
const VLSong * song = [self song];
const VLProperties & prop = song->fProperties.front();
@ -253,79 +176,64 @@ static int sSemiToPitch[] = {
VLFraction swung(3, prop.fDivisions*8, true); // Which notes to swing
VLFraction swingGrid(2*swung); // Alignment of swing notes
for (int system = 0; system<fNumSystems; ++system) {
float kLineY = [self systemY:system];
for (int m = 0; m<fMeasPerSystem; ++m) {
int measIdx = m+system*fMeasPerSystem;
if (measIdx >= song->CountMeasures())
break;
const VLMeasure measure = song->fMeasures[measIdx];
const VLNoteList & melody = measure.fMelody;
VLFraction at(0);
for (VLNoteList::const_iterator note = melody.begin();
note != melody.end();
++note
) {
VLFraction dur = note->fDuration;
BOOL first = !m || !note->fTied;
int pitch = note->fPitch;
while (dur > 0) {
VLFraction partialDur; // Actual value of note drawn
measure.fProperties->PartialNote(at, dur, &partialDur);
float kSystemY = [self systemY:system];
for (int m = 0; m<fMeasPerSystem; ++m) {
int measIdx = m+system*fMeasPerSystem;
if (measIdx >= song->CountMeasures())
break;
const VLMeasure measure = song->fMeasures[measIdx];
const VLNoteList & melody = measure.fMelody;
VLFraction at(0);
for (VLNoteList::const_iterator note = melody.begin();
note != melody.end();
++note
) {
VLFraction dur = note->fDuration;
BOOL first = !m || !note->fTied;
int pitch = note->fPitch;
while (dur > 0) {
VLFraction partialDur; // Actual value of note drawn
measure.fProperties->PartialNote(at, dur, &partialDur);
BOOL triplet = !(partialDur.fDenom % 3);
VLFraction noteDur(1); // Visual value of note
BOOL triplet = !(partialDur.fDenom % 3);
VLFraction noteDur(1); // Visual value of note
if (triplet) {
if (swing) { // Swing 8ths / 16ths are written as straight 8ths
if (partialDur == 4*swung/3 && (at % swingGrid) == 0) {
noteDur = swung;
triplet = NO;
} else if (partialDur == 2*swung/3 && ((at+partialDur) % swingGrid) == 0) {
noteDur = swung;
triplet = NO;
} else {
noteDur = 4*partialDur/3;
}
if (triplet) {
if (swing) { // Swing 8ths / 16ths are written as straight 8ths
if (partialDur == 4*swung/3 && (at % swingGrid) == 0) {
noteDur = swung;
triplet = NO;
} else if (partialDur == 2*swung/3 && ((at+partialDur) % swingGrid) == 0) {
noteDur = swung;
triplet = NO;
} else {
noteDur = 4*partialDur/3;
}
} else {
noteDur = partialDur;
noteDur = 4*partialDur/3;
}
if (pitch != VLNote::kNoPitch)
[self drawNote:noteDur
at: NSMakePoint(
[self noteXInMeasure:m at:at],
kLineY+[self noteYWithPitch:pitch])
tied:!first];
else
[self drawRest:noteDur
at: NSMakePoint(
[self noteXInMeasure:m at:at],
kLineY+[self noteYWithPitch:65])];
dur -= partialDur;
at += partialDur;
first = NO;
} else {
noteDur = partialDur;
}
if (pitch != VLNote::kNoPitch)
[self drawNote:noteDur
at: NSMakePoint(
[self noteXInMeasure:m at:at],
kSystemY+[self noteYWithPitch:pitch])
tied:!first];
else
[self drawRest:noteDur
at: NSMakePoint(
[self noteXInMeasure:m at:at],
kSystemY+[self noteYWithPitch:65])];
dur -= partialDur;
at += partialDur;
first = NO;
}
}
}
if (fNoteCursorMeasure > -1)
if (fCursorPitch != VLNote::kNoPitch && fCursorMeasure/fMeasPerSystem == system)
[self drawNoteCursor];
}
- (void) setNoteCursorMeasure:(int)measure at:(VLFraction)at pitch:(int)pitch
{
if (measure != fNoteCursorMeasure || at != fNoteCursorAt
|| pitch != fNoteCursorPitch
) {
fNoteCursorMeasure = measure;
fNoteCursorAt = at;
fNoteCursorPitch = pitch;
[self setNeedsDisplay:YES];
}
}
@end

View File

@ -200,7 +200,47 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95B042FC0ACE431A00236B52</string>
<string>95DFE83A0AD105A300375606</string>
<key>PBXProjectModuleLabel</key>
<string>VLSheetView.mm</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95DFE83B0AD105A300375606</string>
<key>PBXProjectModuleLabel</key>
<string>VLSheetView.mm</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>95DFE83E0AD105C900375606</string>
<key>history</key>
<array>
<string>95DFE8370AD1053A00375606</string>
</array>
</dict>
<key>SplitCount</key>
<string>1</string>
</dict>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>164 91 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F82E0AB694EC00EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -222,7 +262,7 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95B042FB0ACE431A00236B52</string>
<string>95D1F7FE0AB68C8C00EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -244,7 +284,73 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95B042F70ACE431A00236B52</string>
<string>95D1F8130AB6908400EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>186 75 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8850AB69B6700EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>168 116 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8660AB6970400EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>15 148 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8310AB694EC00EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -288,7 +394,7 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8310AB694EC00EE6AC8</string>
<string>95B042F70ACE431A00236B52</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -310,73 +416,7 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8660AB6970400EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>15 148 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8850AB69B6700EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>168 116 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F8130AB6908400EE6AC8</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict/>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {763, 552}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>186 75 763 593 0 0 1024 746 </string>
</dict>
</dict>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F7FE0AB68C8C00EE6AC8</string>
<string>95B042FB0ACE431A00236B52</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -398,7 +438,7 @@
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>95D1F82E0AB694EC00EE6AC8</string>
<string>95B042FC0ACE431A00236B52</string>
<key>PBXProjectModuleLabel</key>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -450,8 +490,6 @@
<key>Layout</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXBottomSmartGroupGIDs</key>
@ -497,7 +535,7 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>10</integer>
<integer>9</integer>
<integer>1</integer>
<integer>0</integer>
</array>
@ -567,6 +605,8 @@
<string>0pt</string>
</dict>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
@ -603,9 +643,9 @@
</array>
<key>TableOfContents</key>
<array>
<string>9529DCA60AD0E18200C9D67E</string>
<string>95DFE81B0AD0F18B00375606</string>
<string>1CE0B1FE06471DED0097A5F4</string>
<string>9529DCA70AD0E18200C9D67E</string>
<string>95DFE81C0AD0F18B00375606</string>
<string>1CE0B20306471E060097A5F4</string>
<string>1CE0B20506471E060097A5F4</string>
</array>
@ -739,23 +779,24 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>9529DCB30AD0E40700C9D67E</string>
<string>9529DCB40AD0E40700C9D67E</string>
<string>9529DCB50AD0E40700C9D67E</string>
<string>95D7BFC80AA6C1A500D5E02C</string>
<string>95D1F82E0AB694EC00EE6AC8</string>
<string>95D1F7FE0AB68C8C00EE6AC8</string>
<string>95D1F8130AB6908400EE6AC8</string>
<string>95D1F8850AB69B6700EE6AC8</string>
<string>95D1F8660AB6970400EE6AC8</string>
<string>95D1F8310AB694EC00EE6AC8</string>
<string>95B042FA0ACE431A00236B52</string>
<string>95B042F70ACE431A00236B52</string>
<string>95B042FB0ACE431A00236B52</string>
<string>95DFE82C0AD0F29C00375606</string>
<string>95DFE82D0AD0F29C00375606</string>
<string>95DFE82E0AD0F29C00375606</string>
<string>95B042FC0ACE431A00236B52</string>
<string>95B042FB0ACE431A00236B52</string>
<string>95B042F70ACE431A00236B52</string>
<string>95B042FA0ACE431A00236B52</string>
<string>95D1F8310AB694EC00EE6AC8</string>
<string>95D1F8660AB6970400EE6AC8</string>
<string>95D1F8850AB69B6700EE6AC8</string>
<string>95D1F8130AB6908400EE6AC8</string>
<string>95D1F7FE0AB68C8C00EE6AC8</string>
<string>95D1F82E0AB694EC00EE6AC8</string>
<string>1CD10A99069EF8BA00B06720</string>
<string>95D7BFC00AA6C1A500D5E02C</string>
<string>95D7BFC80AA6C1A500D5E02C</string>
<string>/Development/Vocalese/Vocalese.xcodeproj</string>
<string>95DFE83A0AD105A300375606</string>
<string>95D7BFC00AA6C1A500D5E02C</string>
</array>
<key>WindowString</key>
<string>167 326 690 397 0 0 1024 746 </string>
@ -774,14 +815,12 @@
<key>Dock</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>1CD0528F0623707200166675</string>
<key>PBXProjectModuleLabel</key>
<string>VLSheetViewNotes.mm</string>
<string>VLSheetView.mm</string>
<key>StatusBarVisibility</key>
<true/>
</dict>
@ -798,6 +837,8 @@
<string>293pt</string>
</dict>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
@ -837,7 +878,7 @@
<key>TableOfContents</key>
<array>
<string>95D7BFC00AA6C1A500D5E02C</string>
<string>9529DCA80AD0E18200C9D67E</string>
<string>95DFE81D0AD0F18B00375606</string>
<string>1CD0528F0623707200166675</string>
<string>XCMainBuildResultsModuleGUID</string>
</array>
@ -957,13 +998,13 @@
<key>TableOfContents</key>
<array>
<string>1CD10A99069EF8BA00B06720</string>
<string>9529DCA90AD0E18200C9D67E</string>
<string>95DFE81E0AD0F18B00375606</string>
<string>1C162984064C10D400B95A72</string>
<string>9529DCAA0AD0E18200C9D67E</string>
<string>9529DCAB0AD0E18200C9D67E</string>
<string>9529DCAC0AD0E18200C9D67E</string>
<string>9529DCAD0AD0E18200C9D67E</string>
<string>9529DCAE0AD0E18200C9D67E</string>
<string>95DFE81F0AD0F18B00375606</string>
<string>95DFE8200AD0F18B00375606</string>
<string>95DFE8210AD0F18B00375606</string>
<string>95DFE8220AD0F18B00375606</string>
<string>95DFE8230AD0F18B00375606</string>
</array>
<key>ToolbarConfiguration</key>
<string>xcode.toolbar.config.debugV3</string>
@ -1090,6 +1131,8 @@
<key>Dock</key>
<array>
<dict>
<key>BecomeActive</key>
<true/>
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
@ -1125,7 +1168,7 @@
<key>TableOfContents</key>
<array>
<string>95D7BFC80AA6C1A500D5E02C</string>
<string>9529DCB20AD0E40700C9D67E</string>
<string>95DFE82B0AD0F29400375606</string>
<string>1C78EAAC065D492600B07095</string>
</array>
<key>WindowString</key>
@ -1133,7 +1176,7 @@
<key>WindowToolGUID</key>
<string>95D7BFC80AA6C1A500D5E02C</string>
<key>WindowToolIsVisible</key>
<false/>
<true/>
</dict>
<dict>
<key>Identifier</key>

View File

@ -62,8 +62,12 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 181460906;
PBXWorkspaceStateSaveDate = 181460906;
PBXPerProjectTemplateStateSaveDate = 181465162;
PBXWorkspaceStateSaveDate = 181465162;
};
perUserProjectItems = {
95DFE8370AD1053A00375606 /* PBXBookmark */ = 95DFE8370AD1053A00375606 /* PBXBookmark */;
95DFE83E0AD105C900375606 /* PBXTextBookmark */ = 95DFE83E0AD105C900375606 /* PBXTextBookmark */;
};
sourceControlManager = 954D7413095406B2007D9571 /* Source Control */;
userBuildSettings = {
@ -155,9 +159,9 @@
};
952DCD77096BBB11001C2316 /* VLSheetViewChords.mm */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {703, 2114}}";
sepNavSelRange = "{4746, 0}";
sepNavVisRect = "{{0, 1851}, {703, 261}}";
sepNavIntBoundsRect = "{{0, 0}, {703, 1400}}";
sepNavSelRange = "{3987, 0}";
sepNavVisRect = "{{0, 1125}, {703, 261}}";
sepNavWindowFrame = "{{15, 92}, {763, 649}}";
};
};
@ -313,9 +317,9 @@
};
95B66657096BCA1F00FE18C9 /* VLSheetViewNotes.mm */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {703, 4130}}";
sepNavSelRange = "{1225, 0}";
sepNavVisRect = "{{0, 479}, {703, 261}}";
sepNavIntBoundsRect = "{{0, 0}, {703, 2534}}";
sepNavSelRange = "{5830, 0}";
sepNavVisRect = "{{0, 1499}, {703, 261}}";
sepNavWindowFrame = "{{38, 71}, {763, 649}}";
};
};
@ -332,7 +336,7 @@
hitCount = 0;
ignoreCount = 0;
lineNumber = 21;
modificationTime = 181461973.028078;
modificationTime = 181470420.561138;
state = 2;
};
95BDA15709540BF1009F9D65 /* VLSheetView.h */ = {
@ -345,10 +349,24 @@
};
95BDA15809540BF1009F9D65 /* VLSheetView.mm */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {703, 2814}}";
sepNavSelRange = "{8722, 0}";
sepNavVisRect = "{{0, 2553}, {703, 261}}";
sepNavIntBoundsRect = "{{0, 0}, {703, 3584}}";
sepNavSelRange = "{11149, 30}";
sepNavVisRect = "{{0, 3262}, {703, 261}}";
sepNavWindowFrame = "{{164, 35}, {763, 649}}";
};
};
95DFE8370AD1053A00375606 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = 95BDA15809540BF1009F9D65 /* VLSheetView.mm */;
};
95DFE83E0AD105C900375606 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 95BDA15809540BF1009F9D65 /* VLSheetView.mm */;
name = "VLSheetView.mm: 394";
rLen = 0;
rLoc = 9493;
rType = 0;
vrLen = 1225;
vrLoc = 9100;
};
}