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' => [] 'melody' => []
} }
end 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' when 'barline'
@times = nil @times = nil
@type = nil @type = nil
@ -178,7 +185,7 @@ class MusicXMLListener
@meas['coda'] = true @meas['coda'] = true
end end
if attrs['tempo'] if attrs['tempo']
OUTPUT['tempo'] = attrs['tempo'].to_i OUTPUT['tempo'] = attrs['tempo'].to_i
end end
when 'divisions' when 'divisions'
@kind = 'prop' @kind = 'prop'

View File

@ -310,6 +310,11 @@ def _melody
lastProp = meas['properties'] lastProp = meas['properties']
m.add_element(_attributes(INPUT['properties'][lastProp])) m.add_element(_attributes(INPUT['properties'][lastProp]))
end 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'] if meas['coda']
m.add_element 'sound', {'coda' => 'A'} m.add_element 'sound', {'coda' => 'A'}
end end

View File

@ -15,21 +15,34 @@
#include <cstdlib> #include <cstdlib>
#include <cmath> #include <cmath>
VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width) VLSystemLayout::VLSystemLayout(const VLProperties & prop, float width, int maxMeas)
{ {
fDivisions = prop.fDivisions; fDivisions = prop.fDivisions;
fNumGroups = prop.fTime.fNum / std::max(prop.fTime.fDenom / 4, 1); fNumGroups = prop.fTime.fNum / std::max(prop.fTime.fDenom / 4, 1);
fDivPerGroup = fDivisions * prop.fTime.fNum * 4 / (prop.fTime.fDenom * fNumGroups); fDivPerGroup = fDivisions * prop.fTime.fNum * 4 / (prop.fTime.fDenom * fNumGroups);
fClefKeyWidth = kClefX+kClefW+(std::labs(prop.fKey)+1)*kKeyW; fClefKeyWidth = kClefX+kClefW+(std::labs(prop.fKey)+1)*kKeyW;
fMeasureWidth = fNumGroups*(fDivPerGroup+1)*kNoteW; 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) VLLayout::VLLayout(const VLSong & song, float width)
{ {
size_t nextBreak = NextBreak(song);
for (size_t meas = 0; meas<song.fMeasures.size(); ) { 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(); meas += back().NumMeasures();
if (meas >= nextBreak)
nextBreak = NextBreak(song, nextBreak);
} }
} }

View File

@ -13,7 +13,7 @@
class VLSystemLayout { class VLSystemLayout {
public: public:
VLSystemLayout(const VLProperties & prop, float width); VLSystemLayout(const VLProperties & prop, float width, int maxMeas);
float ClefKeyWidth() const { return fClefKeyWidth; } float ClefKeyWidth() const { return fClefKeyWidth; }
float MeasureWidth() const { return fMeasureWidth; } 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() VLMeasure::VLMeasure()
: fPropIdx(0) : fBreak(0), fPropIdx(0)
{ {
} }

View File

@ -239,6 +239,11 @@ typedef std::list<VLChord> VLChordList;
typedef std::list<VLLyricsNote> VLNoteList; typedef std::list<VLLyricsNote> VLNoteList;
struct VLMeasure { struct VLMeasure {
enum {
kNewSystem = 1,
kNewPage = 2
};
uint8_t fBreak;
int8_t fPropIdx; int8_t fPropIdx;
VLChordList fChords; VLChordList fChords;
VLNoteList fMelody; 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"]; [md setObject:[NSNumber numberWithBool:YES] forKey:@"tocoda"];
if (fSong->fCoda == m) if (fSong->fCoda == m)
[md setObject:[NSNumber numberWithBool:YES] forKey:@"coda"]; [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]; [fMeasures addObject:md];
} }
@ -313,6 +317,10 @@ advanceAt:
song->fGoToCoda = measNo+1; song->fGoToCoda = measNo+1;
if ([[mdict objectForKey:@"coda"] boolValue]) if ([[mdict objectForKey:@"coda"] boolValue])
song->fCoda = measNo; 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"]) { if (NSDictionary * beginRep = [mdict objectForKey:@"begin-repeat"]) {
VLRepeat rep; VLRepeat rep;
VLRepeat::Ending ending(measNo, measNo, 0); VLRepeat::Ending ending(measNo, measNo, 0);

View File

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

View File

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

View File

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

View File

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

View File

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