mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 19:23:59 +00:00
Handle system/page breaks
This commit is contained in:
parent
5615dee186
commit
1da7def8bf
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user