2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2011 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 "tremolo.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "note.h"
|
|
|
|
#include "measure.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "stem.h"
|
2014-04-09 16:09:21 +02:00
|
|
|
#include "xml.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Tremolo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-07-17 13:41:50 +02:00
|
|
|
static const char* tremoloName[] = {
|
2014-08-11 12:33:46 +02:00
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "Eighth through stem"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "16th through stem"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "32nd through stem"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "64th through stem"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "Eighth between notes"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "16th between notes"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "32nd between notes"),
|
|
|
|
QT_TRANSLATE_NOOP("Tremolo", "64th between notes")
|
2014-07-17 13:41:50 +02:00
|
|
|
};
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
Tremolo::Tremolo(Score* score)
|
|
|
|
: Element(score)
|
|
|
|
{
|
2014-05-26 11:35:24 +02:00
|
|
|
setTremoloType(TremoloType::R8);
|
2012-05-26 14:26:10 +02:00
|
|
|
_chord1 = 0;
|
|
|
|
_chord2 = 0;
|
2014-05-22 10:10:58 +02:00
|
|
|
setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-10 20:06:00 +02:00
|
|
|
Tremolo::Tremolo(const Tremolo& t)
|
|
|
|
: Element(t)
|
|
|
|
{
|
|
|
|
setTremoloType(t.tremoloType());
|
|
|
|
_chord1 = t.chord1();
|
|
|
|
_chord2 = t.chord2();
|
2014-05-22 10:10:58 +02:00
|
|
|
setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE);
|
2014-05-10 20:06:00 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// draw
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Tremolo::draw(QPainter* painter) const
|
|
|
|
{
|
|
|
|
painter->setBrush(QBrush(curColor()));
|
2012-09-19 17:07:57 +02:00
|
|
|
painter->setPen(Qt::NoPen);
|
2012-05-26 14:26:10 +02:00
|
|
|
painter->drawPath(path);
|
|
|
|
if ((parent() == 0) && !twoNotes()) {
|
|
|
|
qreal x = 0.0; // bbox().width() * .25;
|
2014-05-26 15:31:36 +02:00
|
|
|
QPen pen(curColor(), point(score()->styleS(StyleIdx::stemWidth)));
|
2012-05-26 14:26:10 +02:00
|
|
|
painter->setPen(pen);
|
|
|
|
qreal _spatium = spatium();
|
2013-02-05 20:36:35 +01:00
|
|
|
painter->drawLine(QLineF(x, -_spatium*.5, x, path.boundingRect().height() + _spatium));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2013-03-05 20:23:59 +01:00
|
|
|
// setTremoloType
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-03-05 20:23:59 +01:00
|
|
|
void Tremolo::setTremoloType(TremoloType t)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-03-05 20:23:59 +01:00
|
|
|
_tremoloType = t;
|
|
|
|
switch (tremoloType()) {
|
2014-05-26 11:35:24 +02:00
|
|
|
case TremoloType::R16:
|
|
|
|
case TremoloType::C16:
|
2012-11-14 12:24:08 +01:00
|
|
|
_lines = 2;
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2014-05-26 11:35:24 +02:00
|
|
|
case TremoloType::R32:
|
|
|
|
case TremoloType::C32:
|
2012-11-14 12:24:08 +01:00
|
|
|
_lines = 3;
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2014-05-26 11:35:24 +02:00
|
|
|
case TremoloType::R64:
|
|
|
|
case TremoloType::C64:
|
2012-11-14 12:24:08 +01:00
|
|
|
_lines = 4;
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
default:
|
2012-11-14 12:24:08 +01:00
|
|
|
_lines = 1;
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
2012-11-14 12:24:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// layout
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Tremolo::layout()
|
|
|
|
{
|
|
|
|
qreal _spatium = spatium();
|
|
|
|
|
2014-05-26 15:31:36 +02:00
|
|
|
qreal w2 = _spatium * score()->styleS(StyleIdx::tremoloWidth).val() * .5;
|
|
|
|
qreal h2 = _spatium * score()->styleS(StyleIdx::tremoloBoxHeight).val() * .5;
|
|
|
|
qreal lw = _spatium * score()->styleS(StyleIdx::tremoloStrokeWidth).val();
|
|
|
|
qreal td = _spatium * score()->styleS(StyleIdx::tremoloDistance).val();
|
2012-11-14 12:24:08 +01:00
|
|
|
path = QPainterPath();
|
|
|
|
|
|
|
|
qreal ty = 0.0;
|
|
|
|
for (int i = 0; i < _lines; ++i) {
|
|
|
|
path.moveTo(-w2, ty + h2 - lw);
|
|
|
|
path.lineTo( w2, ty - h2);
|
|
|
|
path.lineTo( w2, ty - h2 + lw);
|
|
|
|
path.lineTo(-w2, ty + h2);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
path.closeSubpath();
|
2012-11-14 12:24:08 +01:00
|
|
|
ty += td;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-02-05 20:36:35 +01:00
|
|
|
|
|
|
|
QRectF rect = path.boundingRect();
|
|
|
|
if ((parent() == 0) && !twoNotes())
|
|
|
|
rect.setHeight(rect.height() + _spatium);
|
|
|
|
setbbox(rect);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
_chord1 = static_cast<Chord*>(parent());
|
|
|
|
if (_chord1 == 0)
|
|
|
|
return;
|
|
|
|
Note* anchor1 = _chord1->upNote();
|
|
|
|
Stem* stem = _chord1->stem();
|
2012-11-14 12:24:08 +01:00
|
|
|
qreal x, y, h;
|
2012-05-26 14:26:10 +02:00
|
|
|
if (stem) {
|
|
|
|
x = stem->pos().x();
|
|
|
|
y = stem->pos().y();
|
|
|
|
h = stem->stemLen();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// center tremolo above note
|
|
|
|
x = anchor1->x() + anchor1->headWidth() * .5;
|
|
|
|
y = anchor1->y();
|
2012-11-14 12:24:08 +01:00
|
|
|
h = 2.0 * _spatium + bbox().height();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (anchor1->line() > 4)
|
|
|
|
h *= -1;
|
|
|
|
}
|
|
|
|
if (!twoNotes()) {
|
2012-11-14 12:24:08 +01:00
|
|
|
//
|
|
|
|
// single note tremolos
|
|
|
|
//
|
|
|
|
bool up = _chord1->up();
|
|
|
|
int line = up ? _chord1->upLine() : _chord1->downLine();
|
|
|
|
static const qreal t[3][2][4][2] = {
|
|
|
|
// normal stem
|
|
|
|
{
|
|
|
|
// DOWN
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ 6, 5 }, // line 1
|
|
|
|
{ 6 - 2 * .8, 5 - 2 * .8 }, // line 2
|
|
|
|
{ 6 - 4 * .8, 3 }, // line 3
|
|
|
|
{ 2 , 3 } // line 4
|
|
|
|
},
|
|
|
|
// UP
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ -6, -5 }, // line 1
|
|
|
|
{ -6, -5 }, // line 2
|
|
|
|
{ -6, -3 - 4 * .8 }, // line 3
|
|
|
|
{ -2 - 6 * .8, -3 - 6 * .8 } // line 4
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// stem with hook
|
|
|
|
{
|
|
|
|
// DOWN
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ 3, 3 }, // line 1
|
|
|
|
{ 2, 2 }, // line 2
|
|
|
|
{ 2, 2 }, // line 3
|
|
|
|
{ 2, 2 } // line 4
|
|
|
|
},
|
|
|
|
// UP
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ -3, -3 }, // line 1
|
|
|
|
{ -2 - 2 * .8, -2 - 2 * .8 }, // line 2
|
|
|
|
{ -2 - 4 * .8, -2 - 4 * .8 }, // line 3
|
|
|
|
{ -2 - 6 * .8, -2 - 6 * .8 } // line 4
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-11-14 12:24:08 +01:00
|
|
|
},
|
|
|
|
// stem with beam
|
|
|
|
{
|
|
|
|
// DOWN
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ 3, 3 }, // line 1
|
|
|
|
{ 2, 2 }, // line 2
|
|
|
|
{ 2, 2 }, // line 3
|
|
|
|
{ 2, 2 } // line 4
|
|
|
|
},
|
|
|
|
// UP
|
|
|
|
{
|
|
|
|
// even line odd line
|
|
|
|
{ -3, -3 }, // line 1
|
|
|
|
{ -2 - 2 * .8, -2 - 2 * .8 }, // line 2
|
|
|
|
{ -2 - 4 * .8, -2 - 4 * .8 }, // line 3
|
|
|
|
{ -2 - 6 * .8, -2 - 6 * .8 } // line 4
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
int idx = _chord1->hook() ? 1 : (_chord1->beam() ? 2 : 0);
|
|
|
|
y = (line + t[idx][up][_lines-1][line & 1]) * _spatium * .5;
|
2012-05-26 14:26:10 +02:00
|
|
|
setPos(x, y);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
y += (h - bbox().height()) * .5;
|
|
|
|
//
|
|
|
|
// two chord tremolo
|
|
|
|
//
|
|
|
|
Segment* s = _chord1->segment()->next();
|
|
|
|
while (s) {
|
2014-06-24 18:36:02 +02:00
|
|
|
if (s->element(track()) && (s->element(track())->type() == Element::Type::CHORD))
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
s = s->next();
|
|
|
|
}
|
|
|
|
if (s == 0) {
|
2014-03-25 13:33:47 +01:00
|
|
|
qDebug("no second note of tremolo found");
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_chord2 = static_cast<Chord*>(s->element(track()));
|
|
|
|
_chord2->setTremolo(this);
|
|
|
|
|
2013-05-23 12:32:40 +02:00
|
|
|
int x2 = _chord2->stemPosBeam().x();
|
|
|
|
int x1 = _chord1->stemPosBeam().x();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// qreal x2 = _chord2->_chord2->up()stemPos(_chord2->up(), true).x();
|
|
|
|
// qreal x1 = _chord1->stemPos(_chord1->up(), true).x();
|
2013-05-23 12:32:40 +02:00
|
|
|
x = x1 - _chord1->pagePos().x() + (x2 - x1 + _chord1->upNote()->headWidth()) * .5;
|
2012-05-26 14:26:10 +02:00
|
|
|
setPos(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// write
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Tremolo::write(Xml& xml) const
|
|
|
|
{
|
2014-07-04 18:19:52 +02:00
|
|
|
if (!xml.canWrite(this)) return;
|
2012-05-26 14:26:10 +02:00
|
|
|
xml.stag(name());
|
2013-03-05 20:23:59 +01:00
|
|
|
xml.tag("subtype", tremoloTypeName());
|
2012-05-26 14:26:10 +02:00
|
|
|
Element::writeProperties(xml);
|
|
|
|
xml.etag();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
void Tremolo::read(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (e.name() == "subtype")
|
2013-03-05 20:23:59 +01:00
|
|
|
setTremoloType(e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (!Element::readProperties(e))
|
2013-01-11 18:10:18 +01:00
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2013-03-05 20:23:59 +01:00
|
|
|
// tremoloTypeName
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-03-05 20:23:59 +01:00
|
|
|
QString Tremolo::tremoloTypeName() const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-03-05 20:23:59 +01:00
|
|
|
switch(tremoloType()) {
|
2014-05-26 11:35:24 +02:00
|
|
|
case TremoloType::R8: return QString("r8");
|
|
|
|
case TremoloType::R16: return QString("r16");
|
|
|
|
case TremoloType::R32: return QString("r32");
|
|
|
|
case TremoloType::R64: return QString("r64");
|
|
|
|
case TremoloType::C8: return QString("c8");
|
|
|
|
case TremoloType::C16: return QString("c16");
|
|
|
|
case TremoloType::C32: return QString("c32");
|
|
|
|
case TremoloType::C64: return QString("c64");
|
2012-05-26 14:26:10 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return QString("??");
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2013-03-05 20:23:59 +01:00
|
|
|
// setTremoloType
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-03-05 20:23:59 +01:00
|
|
|
void Tremolo::setTremoloType(const QString& s)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
TremoloType t;
|
|
|
|
if (s == "r8")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::R8;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "r16")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::R16;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "r32")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::R32;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "r64")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::R64;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "c8")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::C8;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "c16")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::C16;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "c32")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::C32;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (s == "c64")
|
2014-05-26 11:35:24 +02:00
|
|
|
t = TremoloType::C64;
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
t = TremoloType(s.toInt()); // for compatibility with old tremolo type
|
2013-03-05 20:23:59 +01:00
|
|
|
setTremoloType(t);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// tremoloLen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Fraction Tremolo::tremoloLen() const
|
|
|
|
{
|
2012-11-19 09:29:46 +01:00
|
|
|
Fraction f;
|
|
|
|
switch(lines()) {
|
|
|
|
case 1: f.set(1,8); break;
|
|
|
|
case 2: f.set(1,16); break;
|
|
|
|
case 3: f.set(1,32); break;
|
|
|
|
case 4: f.set(1,64); break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-11-19 09:29:46 +01:00
|
|
|
return f;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 13:41:50 +02:00
|
|
|
QString Tremolo::subtypeName() const
|
|
|
|
{
|
|
|
|
return tr(tremoloName[subtype() - int(TremoloType::R8)]);
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
|
|
|
|