mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Handle system/page breaks
This commit is contained in:
parent
5615dee186
commit
1da7def8bf
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -723,13 +743,17 @@ static int8_t sSharpAcc[] = {
|
|||
|
||||
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;
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue
Block a user