//============================================================================= // 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 "vibrato.h" #include "style.h" #include "system.h" #include "measure.h" #include "xml.h" #include "utils.h" #include "sym.h" #include "score.h" #include "accidental.h" #include "segment.h" #include "staff.h" namespace Ms { // must be in sync with Vibrato::Type const VibratoTableItem vibratoTable[] = { { Vibrato::Type::TRILL_LINE, "trill", QT_TRANSLATE_NOOP("trillType", "Vibrato line") }, { Vibrato::Type::UPPRALL_LINE, "upprall", QT_TRANSLATE_NOOP("trillType", "Upprall line") }, { Vibrato::Type::DOWNPRALL_LINE, "downprall", QT_TRANSLATE_NOOP("trillType", "Downprall line") }, { Vibrato::Type::PRALLPRALL_LINE, "prallprall", QT_TRANSLATE_NOOP("trillType", "Prallprall line") }, { Vibrato::Type::GUITAR_VIBRATO, "guitarVibrato", QT_TRANSLATE_NOOP("trillType", "Guitar vibrato") }, { Vibrato::Type::GUITAR_VIBRATO_WIDE, "guitarVibratoWide", QT_TRANSLATE_NOOP("trillType", "Guitar vibrato wide") }, { Vibrato::Type::VIBRATO_SAWTOOTH_NARROW, "vibratoSawtoothNarrow", QT_TRANSLATE_NOOP("trillType", "Vibrato sawtooth narrow") }, { Vibrato::Type::VIBRATO_SAWTOOTH, "vibratoSawtooth", QT_TRANSLATE_NOOP("trillType", "Vibrato sawtooth") }, { Vibrato::Type::VIBRATO_SAWTOOTH_WIDE, "vibratoSawtoothWide", QT_TRANSLATE_NOOP("trillType", "tremolo sawtooth wide") } }; int vibratoTableSize() { return sizeof(vibratoTable)/sizeof(VibratoTableItem); } //--------------------------------------------------------- // draw //--------------------------------------------------------- void VibratoSegment::draw(QPainter* painter) const { painter->setPen(spanner()->curColor()); drawSymbols(_symbols, painter); } //--------------------------------------------------------- // add //--------------------------------------------------------- void VibratoSegment::add(Element* e) { e->setParent(this); if (e->type() == ElementType::ACCIDENTAL) { // accidental is part of trill vibrato()->setAccidental(static_cast(e)); } } //--------------------------------------------------------- // remove //--------------------------------------------------------- void VibratoSegment::remove(Element* e) { if (vibrato()->accidental() == e) { // accidental is part of trill vibrato()->setAccidental(0); } } //--------------------------------------------------------- // symbolLine //--------------------------------------------------------- void VibratoSegment::symbolLine(SymId start, SymId fill) { qreal x1 = 0; qreal x2 = pos2().x(); qreal w = x2 - x1; qreal mag = magS(); ScoreFont* f = score()->scoreFont(); _symbols.clear(); _symbols.push_back(start); qreal w1 = f->advance(start, mag); qreal w2 = f->advance(fill, mag); int n = lrint((w - w1) / w2); for (int i = 0; i < n; ++i) _symbols.push_back(fill); QRectF r(f->bbox(_symbols, mag)); setbbox(r); } void VibratoSegment::symbolLine(SymId start, SymId fill, SymId end) { qreal x1 = 0; qreal x2 = pos2().x(); qreal w = x2 - x1; qreal mag = magS(); ScoreFont* f = score()->scoreFont(); _symbols.clear(); _symbols.push_back(start); qreal w1 = f->bbox(start, mag).width(); qreal w2 = f->width(fill, mag); qreal w3 = f->width(end, mag); int n = lrint((w - w1 - w3) / w2); for (int i = 0; i < n; ++i) _symbols.push_back(fill); _symbols.push_back(end); QRectF r(f->bbox(_symbols, mag)); setbbox(r); } //--------------------------------------------------------- // layout //--------------------------------------------------------- void VibratoSegment::layout() { if (autoplace()) setUserOff(QPointF()); if (staff()) setMag(staff()->mag(tick())); if (isSingleType() || isBeginType()) { Accidental* a = vibrato()->accidental(); if (a) { a->layout(); a->setMag(a->mag() * .6); qreal _spatium = spatium(); a->setPos(_spatium * 1.3, -2.2 * _spatium); a->adjustReadPos(); a->setParent(this); } switch (vibrato()->vibratoType()) { case Vibrato::Type::TRILL_LINE: symbolLine(SymId::ornamentTrill, SymId::wiggleVibrato); break; case Vibrato::Type::PRALLPRALL_LINE: symbolLine(SymId::wiggleVibrato, SymId::wiggleVibrato); break; case Vibrato::Type::UPPRALL_LINE: symbolLine(SymId::ornamentBottomLeftConcaveStroke, SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); break; case Vibrato::Type::DOWNPRALL_LINE: symbolLine(SymId::ornamentLeftVerticalStroke, SymId::ornamentZigZagLineNoRightEnd, SymId::ornamentZigZagLineWithRightEnd); break; case Vibrato::Type::GUITAR_VIBRATO: symbolLine(SymId::guitarVibratoStroke, SymId::guitarVibratoStroke); break; case Vibrato::Type::GUITAR_VIBRATO_WIDE: symbolLine(SymId::guitarWideVibratoStroke, SymId::guitarWideVibratoStroke); break; case Vibrato::Type::VIBRATO_SAWTOOTH_NARROW: symbolLine(SymId::wiggleSawtoothNarrow, SymId::wiggleSawtoothNarrow); break; case Vibrato::Type::VIBRATO_SAWTOOTH: symbolLine(SymId::wiggleSawtooth, SymId::wiggleSawtooth); break; case Vibrato::Type::VIBRATO_SAWTOOTH_WIDE: symbolLine(SymId::wiggleSawtoothWide, SymId::wiggleSawtoothWide); break; } } else symbolLine(SymId::wiggleVibrato, SymId::wiggleVibrato); if (parent()) { qreal yo = score()->styleP(vibrato()->placeBelow() ? StyleIdx::trillPosBelow : StyleIdx::trillPosAbove); rypos() = yo; if (autoplace()) { qreal minDistance = spatium(); Shape s1 = shape().translated(pos()); if (vibrato()->placeAbove()) { qreal d = system()->topDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = -d - minDistance; } else { qreal d = system()->bottomDistance(staffIdx(), s1); if (d > -minDistance) rUserYoffset() = d + minDistance; } } else adjustReadPos(); } } //--------------------------------------------------------- // shape //--------------------------------------------------------- Shape VibratoSegment::shape() const { return Shape(bbox()); } //--------------------------------------------------------- // acceptDrop //--------------------------------------------------------- bool VibratoSegment::acceptDrop(EditData& data) const { if (data.element->isAccidental()) return true; return false; } //--------------------------------------------------------- // drop //--------------------------------------------------------- Element* VibratoSegment::drop(EditData& data) { Element* e = data.element; switch (e->type()) { case ElementType::ACCIDENTAL: e->setParent(vibrato()); score()->undoAddElement(e); break; default: delete e; e = 0; break; } return e; } //--------------------------------------------------------- // getProperty //--------------------------------------------------------- QVariant VibratoSegment::getProperty(P_ID id) const { switch (id) { case P_ID::TRILL_TYPE: case P_ID::ORNAMENT_STYLE: case P_ID::PLACEMENT: case P_ID::PLAY: return vibrato()->getProperty(id); default: return LineSegment::getProperty(id); } } //--------------------------------------------------------- // setProperty //--------------------------------------------------------- bool VibratoSegment::setProperty(P_ID id, const QVariant& v) { switch (id) { case P_ID::TRILL_TYPE: case P_ID::ORNAMENT_STYLE: case P_ID::PLACEMENT: case P_ID::PLAY: return vibrato()->setProperty(id, v); default: return LineSegment::setProperty(id, v); } } //--------------------------------------------------------- // propertyDefault //--------------------------------------------------------- QVariant VibratoSegment::propertyDefault(P_ID id) const { switch (id) { case P_ID::TRILL_TYPE: case P_ID::ORNAMENT_STYLE: case P_ID::PLACEMENT: case P_ID::PLAY: return vibrato()->propertyDefault(id); default: return LineSegment::propertyDefault(id); } } //--------------------------------------------------------- // scanElements //--------------------------------------------------------- void VibratoSegment::scanElements(void* data, void (*func)(void*, Element*), bool /*all*/) { func(data, this); if (isSingleType() || isBeginType()) { Accidental* a = vibrato()->accidental(); if (a) func(data, a); } } //--------------------------------------------------------- // Vibrato //--------------------------------------------------------- Vibrato::Vibrato(Score* s) : SLine(s) { _vibratoType = Type::GUITAR_VIBRATO; _accidental = 0; _ornamentStyle = MScore::OrnamentStyle::DEFAULT; setPlayArticulation(true); setPlacement(Element::Placement::ABOVE); } Vibrato::~Vibrato() { delete _accidental; } //--------------------------------------------------------- // add //--------------------------------------------------------- void Vibrato::add(Element* e) { if (e->type() == ElementType::ACCIDENTAL) { e->setParent(this); _accidental = static_cast(e); } else SLine::add(e); } //--------------------------------------------------------- // remove //--------------------------------------------------------- void Vibrato::remove(Element* e) { if (e == _accidental) _accidental = 0; } //--------------------------------------------------------- // layout //--------------------------------------------------------- void Vibrato::layout() { SLine::layout(); if (score() == gscore) return; if (spannerSegments().empty()) return; VibratoSegment* ls = static_cast(frontSegment()); #if 0 // this is now handled differently, in SLine::linePos // // special case: // if end segment is first chord/rest segment in measure, // shorten trill line so it ends at end of previous measure // qreal _spatium = spatium(); Segment* seg1 = startSegment(); Segment* seg2 = endSegment(); if (seg1 && seg2 && (seg1->system() == seg2->system()) && (spannerSegments().size() == 1) && (seg2->tick() == seg2->measure()->tick()) ) { qreal x1 = seg2->pagePos().x(); Measure* m = seg2->measure()->prevMeasure(); if (m) { Segment* s2 = m->last(); qreal x2 = s2->pagePos().x(); qreal dx = x1 - x2 + _spatium * .3; ls->setPos2(ls->ipos2() + QPointF(-dx, 0.0)); ls->layout(); } } #endif if (spannerSegments().empty()) qDebug("Vibrato: no segments"); if (_accidental) _accidental->setParent(ls); } //--------------------------------------------------------- // createLineSegment //--------------------------------------------------------- LineSegment* Vibrato::createLineSegment() { VibratoSegment* seg = new VibratoSegment(score()); seg->setTrack(track()); seg->setColor(color()); return seg; } //--------------------------------------------------------- // Vibrato::write //--------------------------------------------------------- void Vibrato::write(XmlWriter& xml) const { if (!xml.canWrite(this)) return; xml.stag(QString("%1 id=\"%2\"").arg(name()).arg(xml.spannerId(this))); xml.tag("subtype", vibratoTypeName()); writeProperty(xml, P_ID::PLAY); writeProperty(xml, P_ID::ORNAMENT_STYLE); SLine::writeProperties(xml); if (_accidental) _accidental->write(xml); xml.etag(); } //--------------------------------------------------------- // Vibrato::read //--------------------------------------------------------- void Vibrato::read(XmlReader& e) { qDeleteAll(spannerSegments()); spannerSegments().clear(); e.addSpanner(e.intAttribute("id", -1), this); while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "subtype") setVibratoType(e.readElementText()); else if (tag == "Accidental") { _accidental = new Accidental(score()); _accidental->read(e); _accidental->setParent(this); } else if ( tag == "ornamentStyle") setProperty(P_ID::ORNAMENT_STYLE, Ms::getProperty(P_ID::ORNAMENT_STYLE, e)); else if ( tag == "play") setPlayArticulation(e.readBool()); else if (!SLine::readProperties(e)) e.unknown(); } } //--------------------------------------------------------- // setVibratoType //--------------------------------------------------------- void Vibrato::setVibratoType(const QString& s) { if (s == "0") { _vibratoType = Type::TRILL_LINE; return; } if (s == "pure") { _vibratoType = Type::PRALLPRALL_LINE; // obsolete, compatibility only return; } for (VibratoTableItem i : vibratoTable) { if (s.compare(i.name) == 0) { _vibratoType = i.type; return; } } qDebug("Vibrato::setSubtype: unknown <%s>", qPrintable(s)); } //--------------------------------------------------------- // vibratoTypeName //--------------------------------------------------------- QString Vibrato::vibratoTypeName() const { for (VibratoTableItem i : vibratoTable) { if (i.type == vibratoType()) return i.name; } qDebug("unknown Vibrato subtype %d", int(vibratoType())); return "?"; } //--------------------------------------------------------- // vibratoTypeName //--------------------------------------------------------- QString Vibrato::vibratoTypeUserName() const { return qApp->translate("vibratoType", vibratoTable[static_cast(vibratoType())].userName.toUtf8().constData()); } //--------------------------------------------------------- // scanElements //--------------------------------------------------------- void Vibrato::scanElements(void* data, void (*func)(void*, Element*), bool all) { if (_accidental) _accidental->scanElements(data, func, all); func(data, this); // ? SLine::scanElements(data, func, all); } //--------------------------------------------------------- // getProperty //--------------------------------------------------------- QVariant Vibrato::getProperty(P_ID propertyId) const { switch(propertyId) { case P_ID::TRILL_TYPE: return int(vibratoType()); case P_ID::ORNAMENT_STYLE: return int(ornamentStyle()); case P_ID::PLAY: return bool(playArticulation()); default: break; } return SLine::getProperty(propertyId); } //--------------------------------------------------------- // setProperty //--------------------------------------------------------- bool Vibrato::setProperty(P_ID propertyId, const QVariant& val) { switch(propertyId) { case P_ID::TRILL_TYPE: setVibratoType(Type(val.toInt())); break; case P_ID::PLAY: setPlayArticulation(val.toBool()); break; case P_ID::ORNAMENT_STYLE: setOrnamentStyle(MScore::OrnamentStyle(val.toInt())); break; default: if (!SLine::setProperty(propertyId, val)) return false; break; } score()->setLayoutAll(); return true; } //--------------------------------------------------------- // propertyDefault //--------------------------------------------------------- QVariant Vibrato::propertyDefault(P_ID propertyId) const { switch(propertyId) { case P_ID::TRILL_TYPE: return 0; case P_ID::ORNAMENT_STYLE: //return int(score()->style()->ornamentStyle(_ornamentStyle)); return int(MScore::OrnamentStyle::DEFAULT); case P_ID::PLAY: return true; case P_ID::PLACEMENT: return int(Element::Placement::ABOVE); default: return SLine::propertyDefault(propertyId); } return QVariant(); } //--------------------------------------------------------- // undoSetVibratoType //--------------------------------------------------------- void Vibrato::undoSetVibratoType(Type val) { undoChangeProperty(P_ID::TRILL_TYPE, int(val)); } //--------------------------------------------------------- // setYoff //--------------------------------------------------------- void Vibrato::setYoff(qreal val) { rUserYoffset() += val * spatium() - score()->styleP(StyleIdx::trillPosAbove); } //--------------------------------------------------------- // accessibleInfo //--------------------------------------------------------- QString Vibrato::accessibleInfo() const { return QString("%1: %2").arg(Element::accessibleInfo()).arg(vibratoTypeUserName()); } }