예제 #1
0
Note* searchTieNote114(Note* note)
      {
      Note* note2  = 0;
      Chord* chord = note->chord();
      Segment* seg = chord->segment();
      Part* part   = chord->part();
      int strack   = part->staves()->front()->idx() * VOICES;
      int etrack   = strack + part->staves()->size() * VOICES;

      while ((seg = seg->next1(Segment::Type::ChordRest))) {
            for (int track = strack; track < etrack; ++track) {
                  Chord* c = toChord(seg->element(track));
                  if (c == 0 || (!c->isChord()) || (c->track() != chord->track()))
                        continue;
                  int staffIdx = c->staffIdx() + c->staffMove();
                  if (staffIdx != chord->staffIdx() + chord->staffMove())  // cannot happen?
                        continue;
                  for (Note* n : c->notes()) {
                        if (n->pitch() == note->pitch()) {
                              if (note2 == 0 || c->track() == chord->track())
                                    note2 = n;
                              }
                        }
                  }
            if (note2)
                  break;
            }
      return note2;
      }
예제 #2
0
void Ambitus::updateRange()
      {
      if (!segment())
            return;
      Chord* chord;
      int   firstTrack  = track();
      int   lastTrack   = firstTrack + VOICES-1;
      int   pitchTop    = -1000;
      int   pitchBottom = 1000;
      int   tpcTop      = 0;  // Initialized to prevent warning
      int   tpcBottom   = 0;  // Initialized to prevent warning
      int   trk;
      Measure* meas     = segment()->measure();
      Segment* segm     = meas->findSegment(SegmentType::ChordRest, segment()->tick());
      bool     stop     = meas->sectionBreak();
      while (segm) {
            // moved to another measure?
            if (segm->measure() != meas) {
                  // if section break has been found, stop here
                  if (stop)
                        break;
                  // update meas and stop condition
                  meas = segm->measure();
                  stop = meas->sectionBreak();
                  }
            // scan all relevant tracks of this segment for chords
            for (trk = firstTrack; trk <= lastTrack; trk++) {
                  Element* e = segm->element(trk);
                  if (!e || !e->isChord())
                        continue;
                  chord = toChord(e);
                  // update pitch range (with associated tpc's)
                  for (Note* n : chord->notes()) {
                        if (!n->play())         // skip notes which are not to be played
                              continue;
                        int pitch = n->ppitch();
                        if (pitch > pitchTop) {
                              pitchTop = pitch;
                              tpcTop   = n->tpc();
                              }
                        if (pitch < pitchBottom) {
                              pitchBottom = pitch;
                              tpcBottom   = n->tpc();
                              }
                        }
                  }
            segm = segm->nextCR();
            }

      if (pitchTop > -1000) {             // if something has been found, update this
            _topPitch    = pitchTop;
            _bottomPitch = pitchBottom;
            _topTpc      = tpcTop;
            _bottomTpc   = tpcBottom;
            }
      }
예제 #3
0
Note* nextChordNote(Note* note)
      {
      int         track       = note->track();
      int         fromTrack   = (track / VOICES) * VOICES;
      int         toTrack     = fromTrack + VOICES;
      // TODO : limit to same instrument, not simply to same staff!
      Segment*    seg   = note->chord()->segment()->nextCR(track, true);
      while (seg) {
            Element*    targetElement = seg->elementAt(track);
            // if a chord exists in the same track, return its top note
            if (targetElement && targetElement->isChord())
                  return toChord(targetElement)->upNote();
            // if not, return topmost chord in track range
            for (int i = fromTrack ; i < toTrack; i++) {
                  targetElement = seg->elementAt(i);
                  if (targetElement && targetElement->isChord())
                        return toChord(targetElement)->upNote();
                  }
            seg = seg->nextCR(track, true);
            }
      return nullptr;
      }
예제 #4
0
void Tuplet::layout()
      {
      if (_elements.empty()) {
            qDebug("Tuplet::layout(): tuplet is empty");
            return;
            }
      // is in a TAB without stems, skip any format: tuplets are not shown
      if (staff() && staff()->isTabStaff() && staff()->staffType()->slashStyle())
            return;

      qreal _spatium = spatium();
      if (_numberType != NumberType::NO_TEXT) {
            if (_number == 0) {
                  _number = new Text(score());
                  _number->setTextStyleType(TextStyleType::TUPLET);
                  _number->setTrack(track());
                  _number->setParent(this);
                  _number->setVisible(visible());
                  }
            if (_numberType == NumberType::SHOW_NUMBER)
                  _number->setXmlText(QString("%1").arg(_ratio.numerator()));
            else
                  _number->setXmlText(QString("%1:%2").arg(_ratio.numerator()).arg(_ratio.denominator()));
            }
      else {
            if (_number) {
                  if (_number->selected())
                        score()->deselect(_number);
                  delete _number;
                  _number = 0;
                  }
            }
      //
      // find out main direction
      //
      if (_direction == Direction::AUTO) {
            int up = 1;
            foreach (const DurationElement* e, _elements) {
                  if (e->isChord()) {
                        const Chord* c = toChord(e);
                        if (c->stemDirection() != Direction::AUTO)
                              up += c->stemDirection() == Direction::UP ? 1000 : -1000;
                        else
                              up += c->up() ? 1 : -1;
                        }
                  else if (e->isTuplet()) {
                        // TODO
                        }
                  }
            _isUp = up > 0;
            }
예제 #5
0
bool isTied(const Segment *seg, int strack, int voice,
            Ms::Tie*(Note::*tieFunc)() const)
      {
      ChordRest *cr = static_cast<ChordRest *>(seg->element(strack + voice));
      if (cr && cr->isChord()) {
            Chord *chord = toChord(cr);
            const auto &notes = chord->notes();
            for (const Note *note: notes) {
                  if ((note->*tieFunc)())
                        return true;
                  }
            }
      return false;
      }
예제 #6
0
Dynamic* lookupDynamic(Element* e)
      {
      Dynamic* d = 0;
      Segment* s = 0;
      if (e && e->isChord())
            s = toChord(e)->segment();
      if (s) {
            for (Element* ee : s->annotations()) {
                  if (ee->isDynamic() && ee->track() == e->track() && ee->placeBelow()) {
                        d = toDynamic(ee);
                        break;
                        }
                  }
            }
      if (d) {
            if (!d->autoplace())
                  d = 0;
            }
      return d;
      }
예제 #7
0
Note* searchTieNote(Note* note)
      {
      Note* note2  = 0;
      Chord* chord = note->chord();
      Segment* seg = chord->segment();
      Part* part   = chord->part();
      int strack   = part->staves()->front()->idx() * VOICES;
      int etrack   = strack + part->staves()->size() * VOICES;

      if (chord->isGraceBefore()) {
            // grace before
            // try to tie to note in parent chord
            chord = toChord(chord->parent());
            note2 = chord->findNote(note->pitch());
            if (note2)
                  return note2;
            }
      else if (chord->isGraceAfter()) {
            // grace after
            // we will try to tie to note in next normal chord, below
            // meanwhile, set chord to parent chord so the endTick calculation will make sense
            chord = toChord(chord->parent());
            }
      else {
            // normal chord
            // try to tie to grace note after if present
            QVector<Chord*> gna = chord->graceNotesAfter();
            if (!gna.empty()) {
                  Chord* gc = gna[0];
                  note2 = gc->findNote(note->pitch());
                  if (note2)
                        return note2;
                  }
            }
      // at this point, chord is a regular chord, not a grace chord
      // and we are looking for a note in the *next* chord (grace or regular)

      // calculate end of current note duration
      // but err on the safe side in case there is roundoff in tick count
      int endTick = chord->tick() + chord->actualTicks() - 1;

      while ((seg = seg->next1(Segment::Type::ChordRest))) {
            // skip ahead to end of current note duration as calculated above
            // but just in case, stop if we find element in current track
            if (seg->tick() < endTick  && !seg->element(chord->track()))
                  continue;
            for (int track = strack; track < etrack; ++track) {
                  Element* e = seg->element(track);
                  if (e == 0 || !e->isChord())
                        continue;
                  Chord* c = toChord(e);
                  // if there are grace notes before, try to tie to first one
                  QVector<Chord*> gnb = c->graceNotesBefore();
                  if (!gnb.empty()) {
                        Chord* gc = gnb[0];
                        Note* gn2 = gc->findNote(note->pitch());
                        if (gn2)
                              return gn2;
                        }
                  int staffIdx = c->staffIdx() + c->staffMove();
                  if (staffIdx != chord->staffIdx() + chord->staffMove())  // cannot happen?
                        continue;
                  for (Note* n : c->notes()) {
                        if (n->pitch() == note->pitch()) {
                              if (note2 == 0 || c->track() == chord->track())
                                    note2 = n;
                              }
                        }
                  }
            if (note2)
                  break;
            }
      return note2;
      }
예제 #8
0
void Tremolo::layout()
      {
      qreal _spatium  = spatium() * mag();

      qreal w2  = _spatium * score()->styleS(Sid::tremoloWidth).val() * .5;
      qreal lw  = _spatium * score()->styleS(Sid::tremoloStrokeWidth).val();
      qreal td  = _spatium * score()->styleS(Sid::tremoloDistance).val();
      path      = QPainterPath();

      qreal ty   = 0.0;

      for (int i = 0; i < _lines; i++) {
            path.addRect(-w2, ty, 2.0 * w2, lw);
            ty += td;
            }

      // QRectF rect = path.boundingRect();
      // if ((parent() == 0) && !twoNotes())
      //       rect.setHeight(rect.height() + _spatium);

      _chord1 = toChord(parent());
      if (_chord1 == 0) {
            // just for the palette
            QTransform shearTransform;
            shearTransform.shear(0.0, -(lw / 2.0) / w2);
            path = shearTransform.map(path);
            setbbox(path.boundingRect());
            addbbox(QRectF(bbox().x(), bbox().bottom(), bbox().width(), _spatium));
            return;
            }
      Note* anchor1 = _chord1->upNote();
      Stem* stem    = _chord1->stem();
      qreal x, y, h;
      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();
            h = 2.0 * _spatium + bbox().height();
            if (anchor1->line() > 4)
                  h *= -1;
            }
      if (!twoNotes()) {
            //
            // 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
                        }
                     },
                  // 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 / mag();

            QTransform shearTransform;
            shearTransform.shear(0.0, -(lw / 2.0) / w2);
            path = shearTransform.map(path);

            setbbox(path.boundingRect());
            setPos(x, y);
            return;
            }
      y += (h - bbox().height()) * .5;
      //
      // two chord tremolo
      //
      Segment* s = _chord1->segment()->next();
      while (s) {
            if (s->element(track()) && (s->element(track())->type() == ElementType::CHORD))
                  break;
            s = s->next();
            }
      if (s == 0) {
            qDebug("no second note of tremolo found");
            return;
            }

      _chord2 = toChord(s->element(track()));
      _chord2->setTremolo(this);

      Stem* stem1 = _chord1->stem();
      Stem* stem2 = _chord2->stem();

      // compute the y coordinates of the tips of the stems
      qreal y1, y2;
      qreal firstChordStaffY;

      if (stem2 && stem1) {
            // stemPageYOffset variable is used for the case when the first
            // chord is cross-staff
            firstChordStaffY = stem1->pagePos().y() - stem1->y();  // y coordinate of the staff of the first chord
            y1 = stem1->y() + stem1->p2().y();
            y2 = stem2->pagePos().y() - firstChordStaffY + stem2->p2().y();  // ->p2().y() is better than ->stemLen()
            }
      else {
            firstChordStaffY = _chord1->pagePos().y() - _chord1->y();  // y coordinate of the staff of the first chord
            y1 = _chord1->stemPosBeam().y() - firstChordStaffY + _chord1->defaultStemLength();
            y2 = _chord2->stemPosBeam().y() - firstChordStaffY + _chord2->defaultStemLength();
            }

      // improve the case when one stem is up and another is down
      if (_chord1->beams() == 0 && _chord2->beams() == 0 &&
          _chord1->up() != _chord2->up()) {
            qreal meanNote1Y = .5 * (_chord1->upNote()->pagePos().y() - firstChordStaffY + _chord1->downNote()->pagePos().y() - firstChordStaffY);
            qreal meanNote2Y = .5 * (_chord2->upNote()->pagePos().y() - firstChordStaffY + _chord2->downNote()->pagePos().y() - firstChordStaffY);
            y1 = .5 * (y1 + meanNote1Y);
            y2 = .5 * (y2 + meanNote2Y);
            }

      y = (y1 + y2) * .5;
      if (!_chord1->up()) {
            y -= path.boundingRect().height() * .5;
            }
      if (!_chord2->up()) {
            y -= path.boundingRect().height() * .5;
            }

      // compute the x coordinates of the inner edge of the stems
      qreal x2  = _chord2->stemPosBeam().x();
      if (_chord2->up() && stem2)
            x2 -= stem2->lineWidth();
      qreal x1  = _chord1->stemPosBeam().x();
      if (!_chord1->up() && stem1)
            x1 += stem1->lineWidth();

      x = (x1 + x2) * .5 - _chord1->pagePos().x();

      QTransform xScaleTransform;
      // TODO const qreal H_MULTIPLIER = score()->styleS(Sid::tremoloBeamLengthMultiplier).val();
      const qreal H_MULTIPLIER = 0.62;
      // TODO const qreal MAX_H_LENGTH = _spatium * score()->styleS(Sid::tremoloBeamLengthMultiplier).val();
      const qreal MAX_H_LENGTH = _spatium * 12.0;

      qreal xScaleFactor = qMin(H_MULTIPLIER * (x2 - x1), MAX_H_LENGTH);
      xScaleFactor /= (2.0 * w2);

      xScaleTransform.scale(xScaleFactor, 1.0);
      path = xScaleTransform.map(path);

      qreal beamYOffset = 0.0;

      if (_chord1->beams() == _chord2->beams() && _chord1->beam()) {
            int beams = _chord1->beams();
            qreal beamHalfLineWidth = point(score()->styleS(Sid::beamWidth)) * .5 * mag();
            beamYOffset = beams * _chord1->beam()->beamDist() - beamHalfLineWidth;
            if (_chord1->up() != _chord2->up()) {  // cross-staff
                  beamYOffset = 2 * beamYOffset + beamHalfLineWidth;
                  }
            else if (!_chord1->up() && !_chord2->up()) {
                  beamYOffset = -beamYOffset;
                  }
            }

      QTransform shearTransform;
      if (_chord1->beams() == 0 && _chord2->beams() == 0) {
            if (_chord1->up() && !_chord2->up())
                  shearTransform.shear(0.0, (y2 - y1 - path.boundingRect().height()) / (x2 - x1));
            else if (!_chord1->up() && _chord2->up())
                  shearTransform.shear(0.0, (y2 - y1 + path.boundingRect().height()) / (x2 - x1));
            else
                  shearTransform.shear(0.0, (y2 - y1) / (x2 - x1));
            }
      else {
            shearTransform.shear(0.0, (y2 - y1) / (x2 - x1));
            }

      path = shearTransform.map(path);

      setbbox(path.boundingRect());
      setPos(x, y + beamYOffset);
      }
예제 #9
0
void StringData::fretChords(Chord * chord) const
      {
      int   nFret, minFret, maxFret, nNewFret, nTempFret;
      int   nString, nNewString, nTempString;

      if(bFretting)
            return;
      bFretting = true;

      // we need to keep track of string allocation
      int bUsed[strings()];                    // initially all strings are available
      for(nString=0; nString<strings(); nString++)
            bUsed[nString] = 0;
      // we also need the notes sorted in order of string (from highest to lowest) and then pitch
      QMap<int, Note *> sortedNotes;
      int   count = 0;
      // store staff pitch offset at this tick, to speed up actual note pitch calculations
      // (ottavas not implemented yet)
      int transp = chord->staff() ? chord->part()->instrument()->transpose().chromatic : 0;     // TODO: tick?
      int pitchOffset = /*chord->staff()->pitchOffset(chord->segment()->tick())*/ - transp;
      // if chord parent is not a segment, the chord is special (usually a grace chord):
      // fret it by itself, ignoring the segment
      if (chord->parent()->type() != ElementType::SEGMENT)
            sortChordNotes(sortedNotes, chord, pitchOffset, &count);
      else {
            // scan each chord of seg from same staff as 'chord', inserting each of its notes in sortedNotes
            Segment* seg = chord->segment();
            int trk;
            int trkFrom = (chord->track() / VOICES) * VOICES;
            int trkTo   = trkFrom + VOICES;
            for(trk = trkFrom; trk < trkTo; ++trk) {
                  Element* ch = seg->elist().at(trk);
                  if (ch && ch->type() == ElementType::CHORD)
                        sortChordNotes(sortedNotes, toChord(ch), pitchOffset, &count);
                  }
            }
      // determine used range of frets
      minFret = INT32_MAX;
      maxFret = INT32_MIN;
      foreach(Note* note, sortedNotes) {
            if (note->string() != STRING_NONE)
                  bUsed[note->string()]++;
            if (note->fret() != FRET_NONE && note->fret() < minFret)
                  minFret = note->fret();
            if (note->fret() != FRET_NONE && note->fret() > maxFret)
                  maxFret = note->fret();
      }

      // scan chord notes from highest, matching with strings from the highest
      foreach(Note * note, sortedNotes) {
            nString     = nNewString    = note->string();
            nFret       = nNewFret      = note->fret();
            note->setFretConflict(false);       // assume no conflicts on this note
            // if no fretting (any invalid fretting has been erased by sortChordNotes() )
            if (nString == STRING_NONE /*|| nFret == FRET_NONE || getPitch(nString, nFret) != note->pitch()*/) {
                  // get a new fretting
                  if (!convertPitch(note->pitch(), pitchOffset, &nNewString, &nNewFret) ) {
                        // no way to fit this note in this tab:
                        // mark as fretting conflict
                        note->setFretConflict(true);
                        // store fretting change without affecting chord context
                        if (nFret != nNewFret)
                              note->undoChangeProperty(Pid::FRET, nNewFret);
                        if (nString != nNewString)
                              note->undoChangeProperty(Pid::STRING, nNewString);
                        continue;
                        }
                  // note can be fretted: use string
                  else {
                        bUsed[nNewString]++;
                        }
                  }

            // if the note string (either original or newly assigned) is also used by another note
            if (bUsed[nNewString] > 1) {
                  // attempt to find a suitable string, from topmost
                  for (nTempString=0; nTempString < strings(); nTempString++) {
                        if (bUsed[nTempString] < 1
                                    && (nTempFret=fret(note->pitch(), nTempString, pitchOffset)) != FRET_NONE) {
                              bUsed[nNewString]--;    // free previous string
                              bUsed[nTempString]++;   // and occupy new string
                              nNewFret   = nTempFret;
                              nNewString = nTempString;
                              break;
                              }
                        }
                  }

            // TODO : try to optimize used fret range, avoiding eccessively open positions

            // if fretting did change, store as a fret change
            if (nFret != nNewFret)
                  note->undoChangeProperty(Pid::FRET, nNewFret);
            if (nString != nNewString)
                  note->undoChangeProperty(Pid::STRING, nNewString);
            }