Handle system/page breaks

This commit is contained in:
Matthias Neeracher 2007-12-23 23:07:27 +00:00
parent 5615dee186
commit 1da7def8bf
12 changed files with 81 additions and 17 deletions

View File

@ -158,6 +158,13 @@ class MusicXMLListener
'melody' => []
}
end
when 'print'
if attrs['new-system'] == 'yes'
@meas['new-system'] = true
end
if attrs['new-page'] == 'yes'
@meas['new-page'] = true
end
when 'barline'
@times = nil
@type = nil
@ -178,7 +185,7 @@ class MusicXMLListener
@meas['coda'] = true
end
if attrs['tempo']
OUTPUT['tempo'] = attrs['tempo'].to_i
OUTPUT['tempo'] = attrs['tempo'].to_i
end
when 'divisions'
@kind = 'prop'

View File

@ -310,6 +310,11 @@ def _melody
lastProp = meas['properties']
m.add_element(_attributes(INPUT['properties'][lastProp]))
end
if meas['new-page']
m.add_element 'print', {'new-page' => 'yes'}
elsif meas['new-system']
m.add_element 'print', {'new-system' => 'yes'}
end
if meas['coda']
m.add_element 'sound', {'coda' => 'A'}
end

View File

@ -15,21 +15,34 @@
#include <cstdlib>
#include <cmath>
VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width)
VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width, int maxMeas)
{
fDivisions = prop.fDivisions;
fNumGroups = prop.fTime.fNum / std::max(prop.fTime.fDenom / 4, 1);
fDivPerGroup = fDivisions * prop.fTime.fNum * 4 / (prop.fTime.fDenom * fNumGroups);
fClefKeyWidth = kClefX+kClefW+(std::labs(prop.fKey)+1)*kKeyW;
fMeasureWidth = fNumGroups*(fDivPerGroup+1)*kNoteW;
fNumMeasures= std::max<int>(1, std::floor((width-fClefKeyWidth) / fMeasureWidth));
fNumMeasures = std::min(maxMeas,
std::max<int>(1,
std::floor((width-fClefKeyWidth) / fMeasureWidth)));
}
static size_t NextBreak(const VLSong & song, size_t after=0)
{
while (++after < song.fMeasures.size())
if (song.fMeasures[after].fBreak)
return after;
return song.fMeasures.size();
}
VLLayout::VLLayout(const VLSong & song, float width)
{
size_t nextBreak = NextBreak(song);
for (size_t meas = 0; meas<song.fMeasures.size(); ) {
push_back(VLSystemLayout(song.Properties(meas), width));
push_back(VLSystemLayout(song.Properties(meas), width, nextBreak-meas));
meas += back().NumMeasures();
if (meas >= nextBreak)
nextBreak = NextBreak(song, nextBreak);
}
}

View File

@ -13,7 +13,7 @@
class VLSystemLayout {
public:
VLSystemLayout(const VLProperties & prop, float width);
VLSystemLayout(const VLProperties & prop, float width, int maxMeas);
float ClefKeyWidth() const { return fClefKeyWidth; }
float MeasureWidth() const { return fMeasureWidth; }

View File

@ -376,7 +376,7 @@ void VLChord::Name(std::string & base, std::string & ext, std::string & root, bo
}
VLMeasure::VLMeasure()
: fPropIdx(0)
: fBreak(0), fPropIdx(0)
{
}

View File

@ -239,6 +239,11 @@ typedef std::list<VLChord> VLChordList;
typedef std::list<VLLyricsNote> VLNoteList;
struct VLMeasure {
enum {
kNewSystem = 1,
kNewPage = 2
};
uint8_t fBreak;
int8_t fPropIdx;
VLChordList fChords;
VLNoteList fMelody;

View File

@ -119,6 +119,10 @@ void VLPlistVisitor::VisitMeasure(size_t m, VLProperties & p, VLMeasure & meas)
[md setObject:[NSNumber numberWithBool:YES] forKey:@"tocoda"];
if (fSong->fCoda == m)
[md setObject:[NSNumber numberWithBool:YES] forKey:@"coda"];
if (meas.fBreak & VLMeasure::kNewSystem)
[md setObject:[NSNumber numberWithBool:YES] forKey:@"new-system"];
if (meas.fBreak & VLMeasure::kNewPage)
[md setObject:[NSNumber numberWithBool:YES] forKey:@"new-page"];
[fMeasures addObject:md];
}
@ -313,6 +317,10 @@ advanceAt:
song->fGoToCoda = measNo+1;
if ([[mdict objectForKey:@"coda"] boolValue])
song->fCoda = measNo;
if ([[mdict objectForKey:@"new-system"] boolValue])
song->fMeasures[measNo].fBreak |= VLMeasure::kNewSystem;
if ([[mdict objectForKey:@"new-page"] boolValue])
song->fMeasures[measNo].fBreak |= VLMeasure::kNewPage;
if (NSDictionary * beginRep = [mdict objectForKey:@"begin-repeat"]) {
VLRepeat rep;
VLRepeat::Ending ending(measNo, measNo, 0);

View File

@ -263,7 +263,7 @@ VLMusicElement sSemi2Accidental[12][12] = {
delete fLayout;
fLayout = new VLLayout(*[self song], sz.width / fDisplayScale);
sz.height = fLayout->NumSystems()*kSystemH;
sz.height = std::max(2, fLayout->NumSystems())*kSystemH;
NSSize boundsSz = {sz.width / fDisplayScale, sz.height / fDisplayScale};
@ -283,15 +283,24 @@ VLMusicElement sSemi2Accidental[12][12] = {
fNeedsRecalc = kNoRecalc;
}
const char * sBreak[3] = {"", "\xE2\xA4\xBE", "\xE2\x8E\x98"};
- (void)drawGridForSystem:(int)system
{
static NSDictionary * sMeasNoFont = nil;
static NSDictionary * sBreakFont = nil;
if (!sMeasNoFont)
sMeasNoFont =
[[NSDictionary alloc] initWithObjectsAndKeys:
[NSFont fontWithName: @"Helvetica" size: 10],
NSFontAttributeName,
nil];
if (!sBreakFont)
sBreakFont =
[[NSDictionary alloc] initWithObjectsAndKeys:
[NSFont fontWithName: @"Symbol" size: 30],
NSFontAttributeName,
nil];
const VLSystemLayout & kLayout = (*fLayout)[system];
const VLSong * song = [self song];
@ -468,6 +477,17 @@ VLMusicElement sSemi2Accidental[12][12] = {
x += kAccW;
}
}
//
// Draw break character
//
int breakType = 0;
int nextMeasure = fLayout->FirstMeasure(system+1);
if (nextMeasure < song->fMeasures.size())
breakType = song->fMeasures[nextMeasure].fBreak;
if (breakType)
[[NSString stringWithUTF8String:sBreak[breakType]]
drawAtPoint: NSMakePoint(kLineX+kLineW+kBreakX, kSystemY+kBreakY)
withAttributes: sBreakFont];
}
- (void)drawBackgroundForSystem:(int)system
@ -721,15 +741,19 @@ static int8_t sSharpAcc[] = {
{
fCursorPitch = VLNote::kNoPitch;
NSPoint loc = [event locationInWindow];
loc = [self convertPoint:loc fromView:nil];
NSPoint loc = [event locationInWindow];
loc = [self convertPoint:loc fromView:nil];
const int kNumSystems = std::max(2, fLayout->NumSystems());
if (loc.y < 0.0f || loc.y >= fLayout->NumSystems()*kSystemH)
if (loc.y < 0.0f || loc.y >= kNumSystems*kSystemH)
return fCursorRegion = kRegionNowhere;
const VLSong * song = [self song];
int system =
fLayout->NumSystems() - static_cast<int>(loc.y / kSystemH) - 1;
int system =
kNumSystems - static_cast<int>(loc.y / kSystemH) - 1;
if (system >= fLayout->NumSystems())
return fCursorRegion = kRegionNowhere;
const VLSystemLayout & kLayout = (*fLayout)[system];
const float kMeasureW = kLayout.MeasureWidth();
loc.y = fmodf(loc.y, kSystemH);

View File

@ -248,7 +248,7 @@ std::string NormalizeName(NSString* rawName)
) {
NSAttributedString * chordName = [self stringWithChord:*chord];
NSPoint chordLoc =
NSMakePoint([self noteXInMeasure:m at:at], kSystemY+kChordY);
NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY+kChordY);
[chordName drawAtPoint:chordLoc];
at += chord->fDuration;
}

View File

@ -19,6 +19,8 @@ const float kClefW = 30.0f;
const float kMeasTol = 3.5f;
const float kMeasNoX = 10.0f;
const float kMeasNoY = 4.5f*kLineH;
const float kBreakX = 5.0f;
const float kBreakY = 0.0f*kLineH;
const float kNoteW = 12.0f;
const float kKeyW = 10.0f;
const float kAccW = 10.0f;

View File

@ -142,7 +142,7 @@
NSSize sz =
[syll sizeWithAttributes:sLyricsFont];
NSPoint syllLoc =
NSMakePoint([self noteXInMeasure:m at:at]
NSMakePoint([self noteXInMeasure:measIdx at:at]
- 0.5f*sz.width,
kSystemY+kLyricsY-stanza*kLyricsH);
if (note->fLyrics[stanza-1].fKind & VLSyllable::kHasNext)

View File

@ -302,10 +302,10 @@
int pitch = note->fPitch;
if (pitch != VLNote::kNoPitch) {
[self drawLedgerLinesWithPitch:pitch
at:NSMakePoint([self noteXInMeasure:m at:at], kSystemY)];
at:NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY)];
VLMusicElement accidental;
NSPoint pos =
NSMakePoint([self noteXInMeasure:m at:at],
NSMakePoint([self noteXInMeasure:measIdx at:at],
kSystemY+[self noteYWithPitch:pitch
accidental:&accidental]);
VLMusicElement acc = accidental;
@ -325,7 +325,7 @@
} else {
VLMusicElement accidental;
NSPoint pos =
NSMakePoint([self noteXInMeasure:m at:at],
NSMakePoint([self noteXInMeasure:measIdx at:at],
kSystemY+[self noteYWithPitch:65
accidental:&accidental]);
[self drawRest:note->fVisual & VLNote::kNoteHead at: pos];