MuseScore/libmscore/groups.cpp
2013-05-27 19:07:03 +02:00

218 lines
6.5 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2013 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "groups.h"
#include "durationtype.h"
#include "chordrest.h"
#include "staff.h"
#include "tuplet.h"
namespace Ms {
//---------------------------------------------------------
// noteGroups
//---------------------------------------------------------
static std::vector<NoteGroup> noteGroups {
{ Fraction(4,4),
Groups( { { 4, 768}, { 8, 272}, {12, 768}, {16, 273}, {20, 768}, {24, 272}, {28, 768} })
},
{ Fraction(3,4),
Groups( { { 8, 273}, {16, 273} })
},
{ Fraction(2,4),
Groups( { { 8, 273}, {0, 0} })
},
{ Fraction(6,8),
Groups( { { 12, 273}, {0, 0} })
},
{ Fraction(12,8),
Groups( { { 12, 273}, {24, 273}, {36, 273} })
},
};
//---------------------------------------------------------
// endBeam
//---------------------------------------------------------
BeamMode Groups::endBeam(ChordRest* cr)
{
if (cr->beamMode() != BeamMode::AUTO)
return cr->beamMode();
Q_ASSERT(cr->staff());
if (cr->tuplet() && !cr->tuplet()->elements().isEmpty()) {
if (cr->tuplet()->elements().front() == cr) // end beam at new tuplet
return BeamMode::BEGIN;
if (cr->tuplet()->elements().back() == cr) // end beam at tuplet end
return BeamMode::END;
return BeamMode::AUTO;
}
TDuration d = cr->durationType();
const Groups& g = cr->staff()->group(cr->tick());
return g.beamMode(cr->rtick(), d.type());
}
//---------------------------------------------------------
// beamMode
//---------------------------------------------------------
BeamMode Groups::beamMode(int tick, TDuration::DurationType d) const
{
int shift;
switch (d) {
case TDuration::DurationType::V_EIGHT: shift = 0; break;
case TDuration::DurationType::V_16TH: shift = 4; break;
case TDuration::DurationType::V_32ND: shift = 8; break;
default:
return BeamMode::AUTO;
}
for (const GroupNode& e : *this) {
if (e.pos * 60 < tick)
continue;
if (e.pos * 60 > tick)
break;
int action = (e.action >> shift) & 0xf;
switch (action) {
case 0: return BeamMode::AUTO;
case 1: return BeamMode::BEGIN;
case 2: return BeamMode::BEGIN32;
case 3: return BeamMode::BEGIN64;
default:
qDebug(" Groups::beamMode: bad action %d", action);
return BeamMode::AUTO;
}
}
return BeamMode::AUTO;
}
//---------------------------------------------------------
// endings
//---------------------------------------------------------
const Groups& Groups::endings(const Fraction& f)
{
for (const NoteGroup& g : noteGroups) {
if (g.timeSig.identical(f)) {
return g.endings;
}
}
NoteGroup g;
g.timeSig = f;
noteGroups.push_back(g);
int pos = 0;
switch(f.denominator()) {
case 2: pos = 16; break;
case 4: pos = 8; break;
case 8: pos = 4; break;
case 16: pos = 2; break;
case 32: pos = 1; break;
break;
}
for (int i = 1; i < f.numerator(); ++i) {
GroupNode n;
n.pos = pos * i;
n.action = 0x111;
g.endings.push_back(n);
}
return noteGroups.back().endings;
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Groups::write(Xml& xml) const
{
xml.stag("Groups");
for (const GroupNode& n : *this)
xml.tagE(QString("Node pos=\"%1\" action=\"%3\"")
.arg(n.pos).arg(n.action));
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void Groups::read(XmlReader& e)
{
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
if (tag == "Node") {
GroupNode n;
n.pos = e.intAttribute("pos");
n.action = e.intAttribute("action");
push_back(n);
e.skipCurrentElement();
}
else
e.unknown();
}
}
//---------------------------------------------------------
// addStop
//---------------------------------------------------------
void Groups::addStop(int pos, TDuration::DurationType d, BeamMode bm)
{
int shift;
switch (d) {
case TDuration::DurationType::V_EIGHT: shift = 0; break;
case TDuration::DurationType::V_16TH: shift = 4; break;
case TDuration::DurationType::V_32ND: shift = 8; break;
default:
return;
}
int action;
if (bm == BeamMode::BEGIN)
action = 1;
else if (bm == BeamMode::BEGIN32)
action = 2;
else if (bm == BeamMode::BEGIN64)
action = 3;
else
return;
pos /= 60;
action <<= shift;
auto i = begin();
for (; i != end(); ++i) {
if (i->pos == pos) {
i->action = (i->action & ~(0xf << shift)) | action;
return;
}
if (i->pos > pos)
break;
}
insert(i, GroupNode({ pos, action }));
}
//---------------------------------------------------------
// dump
//---------------------------------------------------------
void Groups::dump(const char* m) const
{
printf("%s\n", m);
for (const GroupNode& n : *this) {
printf(" group tick %d action 0x%02x\n", n.pos * 60, n.action);
}
}
}