    //=============================================================================
    //  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 "durationtype.h"
    #include "mscore.h"
    #include "note.h"
    #include "sig.h"
    #include "measure.h"

    namespace Ms {

    static const int POW_MAX_DOTS = qPow(2, MAX_DOTS);

    //---------------------------------------------------------
    //   dots
    //---------------------------------------------------------

    static int getDots(int base, int rest, char* dots)
          {
          if (base < 16)
               return rest;
          *dots = 0;
          if (rest >= base / 2) {
                *dots = *dots + 1;
                rest -= base / 2;
                }
          if (rest >= base / 4) {
                *dots = *dots + 1;
                rest -= base / 4;
                }
          if (rest >= base / 8) {
                *dots = *dots + 1;
                rest -= base / 8;
                }
          if (rest >= base / 16) {
                *dots = *dots + 1;
                rest -= base / 16;
                }
          if (*dots > MAX_DOTS)
                *dots = MAX_DOTS;
          return rest;
          }

    //---------------------------------------------------------
    //   setDots
    //---------------------------------------------------------

    void TDuration::setDots(int v)
          {
          if (v > MAX_DOTS)
                v = MAX_DOTS;
          _dots = v;
          }

    //---------------------------------------------------------
    //   setVal
    //---------------------------------------------------------

    void TDuration::setVal(int ticks)
          {
          if (ticks == 0)
                _val = DurationType::V_MEASURE;
          else {
                TDuration dt;
                for (int i = 0; i < int(TDuration::DurationType::V_ZERO); ++i) {
                      dt.setType(TDuration::DurationType(i));
                      int t = dt.ticks();
                      if (ticks / t) {
                            int remain = ticks % t;
                            if ((t - remain) < (t/4)) {
                                  _val = DurationType(i - 1);
                                  return;
                                  }
                            _val = DurationType(i);
                            getDots(t, remain, &_dots);
                            return;
                            }
                      }
                qDebug("2: no duration type for ticks %d", ticks);
                _val = DurationType::V_QUARTER;       // fallback default value
                }
          }

    //---------------------------------------------------------
    //   ticks
    //---------------------------------------------------------

    int TDuration::ticks() const
          {
          int t;
          switch(_val) {
                case DurationType::V_QUARTER:   t = MScore::division;        break;
                case DurationType::V_1024TH:    t = MScore::division / 256;  break;
                case DurationType::V_512TH:     t = MScore::division / 128;  break;
                case DurationType::V_256TH:     t = MScore::division / 64;   break;
                case DurationType::V_128TH:     t = MScore::division / 32;   break;
                case DurationType::V_64TH:      t = MScore::division / 16;   break;
                case DurationType::V_32ND:      t = MScore::division / 8;    break;
                case DurationType::V_16TH:      t = MScore::division / 4;    break;
                case DurationType::V_EIGHTH:    t = MScore::division / 2;    break;
                case DurationType::V_HALF:      t = MScore::division * 2;    break;
                case DurationType::V_WHOLE:     t = MScore::division * 4;    break;
                case DurationType::V_BREVE:     t = MScore::division * 8;    break;
                case DurationType::V_LONG:      t = MScore::division * 16;   break;
                case DurationType::V_ZERO:
                case DurationType::V_MEASURE:
                      return 0;
                default:
                case DurationType::V_INVALID:
                      return -1;
                }
          int tmp = t;
          for (int i = 0; i < _dots; ++i)
                tmp += (t >> (i+1));
          return tmp;
          }

    //---------------------------------------------------------
    //   name
    //---------------------------------------------------------

    QString TDuration::name() const
          {
          switch(_val) {
                case DurationType::V_QUARTER:   return "quarter";
                case DurationType::V_EIGHTH:    return "eighth";
                case DurationType::V_1024TH:    return "1024th";
                case DurationType::V_512TH:     return "512th";
                case DurationType::V_256TH:     return "256th";
                case DurationType::V_128TH:     return "128th";
                case DurationType::V_64TH:      return "64th";
                case DurationType::V_32ND:      return "32nd";
                case DurationType::V_16TH:      return "16th";
                case DurationType::V_HALF:      return "half";
                case DurationType::V_WHOLE:     return "whole";
                case DurationType::V_MEASURE:   return "measure";
                case DurationType::V_BREVE:     return "breve";
                case DurationType::V_LONG:      return "long";
                default:
    qDebug("TDuration::name(): invalid duration type %d", static_cast<int>(_val));
                     // fall through
                case DurationType::V_ZERO:
                case DurationType::V_INVALID:   return "";
                }
          }

    //---------------------------------------------------------
    //   headType
    //---------------------------------------------------------

    NoteHead::Type TDuration::headType() const
          {
          NoteHead::Type headType = NoteHead::Type::HEAD_WHOLE;
          switch(_val) {
                case DurationType::V_1024TH:
                case DurationType::V_512TH:
                case DurationType::V_256TH:
                case DurationType::V_128TH:
                case DurationType::V_64TH:
                case DurationType::V_32ND:
                case DurationType::V_16TH:
                case DurationType::V_EIGHTH:
                case DurationType::V_QUARTER:
                      headType = NoteHead::Type::HEAD_QUARTER;
                      break;
                case DurationType::V_HALF:
                      headType = NoteHead::Type::HEAD_HALF;
                      break;
                case DurationType::V_MEASURE:
                case DurationType::V_WHOLE:
                      headType = NoteHead::Type::HEAD_WHOLE;
                      break;
                case DurationType::V_BREVE:
                      headType = NoteHead::Type::HEAD_BREVIS;
                      break;
                case DurationType::V_LONG:
                      headType = NoteHead::Type::HEAD_BREVIS;
                      break;
                default:
                case DurationType::V_INVALID:
                case DurationType::V_ZERO:
                      headType = NoteHead::Type::HEAD_QUARTER;
                      break;
                }
          return headType;
          }

    //---------------------------------------------------------
    //   hooks
    //---------------------------------------------------------

    int TDuration::hooks() const
          {
          static const int table[] = {
             // V_LONG, V_BREVE, V_WHOLE, V_HALF, V_QUARTER, V_EIGHTH, V_16TH,
                0,      0,       0,       0,      0,         1,        2,
             // V_32ND, V_64TH, V_128TH, V_256TH, V_512TH, V_1024TH,
                3,      4,       5,       6,      7,       8,
             // V_ZERO, V_MEASURE, V_INVALID
                0,      0,       0
                };
          return table[int(_val)];
          }

    //---------------------------------------------------------
    //   hasStem
    //---------------------------------------------------------

    bool TDuration::hasStem() const
          {
          switch(_val) {
                case DurationType::V_1024TH:
                case DurationType::V_512TH:
                case DurationType::V_256TH:
                case DurationType::V_128TH:
                case DurationType::V_64TH:
                case DurationType::V_32ND:
                case DurationType::V_16TH:
                case DurationType::V_EIGHTH:
                case DurationType::V_QUARTER:
                case DurationType::V_HALF:
                case DurationType::V_LONG:
                      return true;
                default:
                      return false;
                }
          }

    //---------------------------------------------------------
    //   setVal
    //---------------------------------------------------------

    TDuration::TDuration(const QString& s)
          {
          setType(s);
          _dots = 0;
          }

    //---------------------------------------------------------
    //   setType
    //---------------------------------------------------------

    void TDuration::setType(const QString& s)
          {
          if (s == "quarter")
                _val = DurationType::V_QUARTER;
          else if (s == "eighth")
                _val = DurationType::V_EIGHTH;
          else if (s == "1024th")
                _val = DurationType::V_1024TH;
          else if (s == "512th")
                _val = DurationType::V_512TH;
          else if (s == "256th")
                _val = DurationType::V_256TH;
          else if (s == "128th")
                _val = DurationType::V_128TH;
          else if (s == "64th")
                _val = DurationType::V_64TH;
          else if (s == "32nd")
                _val = DurationType::V_32ND;
          else if (s == "16th")
                _val = DurationType::V_16TH;
          else if (s == "half")
                _val = DurationType::V_HALF;
          else if (s == "whole")
                _val = DurationType::V_WHOLE;
          else if (s == "breve")
                _val = DurationType::V_BREVE;
          else if (s == "long")
                _val = DurationType::V_LONG;
          else if (s == "measure")
                _val = DurationType::V_MEASURE;
          else {
                // _val = V_INVALID;
                _val = DurationType::V_QUARTER;
                qDebug("TDuration::setType(%s): unknown, assume \"quarter\"", qPrintable(s));
                }
          }

    //---------------------------------------------------------
    //   shiftType
    //    if stepDotted = false, duration type will inc/dec by nSteps with _dots remaining same
    //    if stepDotted = true, duration will round toward zero to next single-dotted or undotted duration and then will included dotted durations when stepping
    //---------------------------------------------------------

    void TDuration::shiftType(int nSteps, bool stepDotted)
          {
          if (_val == DurationType::V_MEASURE || _val == DurationType::V_INVALID || _val == DurationType::V_ZERO)
                setType(DurationType::V_INVALID);
          else {
                int newValue;
                int newDots;
                if (stepDotted) {
                      // figure out the new duration in terms of the number of single dotted or undotted steps from DurationType::V_LONG
                      int roundDownSingleDots = (_dots > 0) ? -1 : 0;
                      int newValAsNumSingleDotSteps = int(_val) * 2 + roundDownSingleDots + nSteps;

                      // convert that new duration back into terms of DurationType integer value and number of dots
                      newDots = newValAsNumSingleDotSteps % 2; // odd means there is a dot
                      newValue = newValAsNumSingleDotSteps / 2 + newDots; // if new duration has a dot, then that
                      }
                else {
                      newDots = _dots;
                      newValue = int(_val) + nSteps;
                      }

                if ((newValue < int(DurationType::V_LONG)) || (newValue > int(DurationType::V_1024TH)) ||
                     ((newValue >= int(DurationType::V_1024TH)) && (newDots >= 1)) ||
                     ((newValue >= int(DurationType::V_512TH))  && (newDots >= 2)) ||
                     ((newValue >= int(DurationType::V_256TH))  && (newDots >= 3)) ||
                     ((newValue >= int(DurationType::V_128TH))  && (newDots >= 4)))
                      setType(DurationType::V_INVALID);
                else {
                      setType(DurationType(newValue));
                      setDots(newDots);
                      }
                }
          }

    //---------------------------------------------------------
    //   operator<
    //---------------------------------------------------------

    bool TDuration::operator<(const TDuration& t) const
          {
          if (t._val < _val)
                return true;
          if (t._val == _val) {
                if (_dots < t._dots)
                      return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   operator>=
    //---------------------------------------------------------

    bool TDuration::operator>=(const TDuration& t) const
          {
          if (t._val > _val)
                return true;
          if (t._val == _val) {
                if (_dots >= t._dots)
                      return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   operator<=
    //---------------------------------------------------------

    bool TDuration::operator<=(const TDuration& t) const
          {
          if (t._val < _val)
                return true;
          if (t._val == _val) {
                if (_dots <= t._dots)
                      return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   operator>
    //---------------------------------------------------------

    bool TDuration::operator>(const TDuration& t) const
          {
          if (t._val > _val)
                return true;
          if (t._val == _val) {
                if (_dots > t._dots)
                      return true;
                }
          return false;
          }

    //---------------------------------------------------------
    //   fraction
    //---------------------------------------------------------

    Fraction TDuration::fraction() const
          {
          int z = 1;
          unsigned n;
          switch(_val) {
                case DurationType::V_1024TH:    n = 1024;     break;
                case DurationType::V_512TH:     n = 512;      break;
                case DurationType::V_256TH:     n = 256;      break;
                case DurationType::V_128TH:     n = 128;      break;
                case DurationType::V_64TH:      n = 64;       break;
                case DurationType::V_32ND:      n = 32;       break;
                case DurationType::V_16TH:      n = 16;       break;
                case DurationType::V_EIGHTH:    n = 8;        break;
                case DurationType::V_QUARTER:   n = 4;        break;
                case DurationType::V_HALF:      n = 2;        break;
                case DurationType::V_WHOLE:     n = 1;        break;
                case DurationType::V_BREVE:     z = 2; n = 1; break;
                case DurationType::V_LONG:      z = 4; n = 1; break;
                case DurationType::V_ZERO:      z = 0; n = 1; break;
                default:          z = 0; n = 0; break;    // zero+invalid fraction
                }
          Fraction a(z, n);
          if (a.isValid()) {
                for (int i = 0; i < _dots; ++i) {
                      n *= 2;
                      a += Fraction(z, n);
                      }
                }
          return a;
          }

    // Longest TDuration that fits into Fraction. Must fit exactly if truncate = false.
    TDuration::TDuration(const Fraction& l, bool truncate, int maxDots, DurationType maxType)
          {
    #ifdef NDEBUG
          Q_UNUSED(truncate);
    #endif
          setType(maxType); // use maxType to avoid testing all types if you know that l is smaller than a certain DurationType
          setDots(maxDots);
          truncateToFraction(l, maxDots);
          Q_ASSERT(truncate || (fraction() - l).numerator() == 0); // check for exact fit
          }

    //---------------------------------------------------------
    //   truncateToFraction
    //---------------------------------------------------------

    void TDuration::truncateToFraction(const Fraction& l, int maxDots)
          {
          // try to fit in l by reducing number of duration dots
          if (setDotsToFitFraction(l, _dots))
                return;

          // that wasn't enough so now change type too
          for (shiftType(1); isValid(); shiftType(1)) {
                if (setDotsToFitFraction(l, maxDots))
                      return; // duration fits fits in l
                }

          }

    //---------------------------------------------------------
    //   setDotsToFitFraction
    //---------------------------------------------------------

    bool TDuration::setDotsToFitFraction(const Fraction& l, int maxDots)
          {
          for ( ; maxDots >= 0; maxDots--) {
                _dots = maxDots; // ensures _dots >= 0 if function returns false.
                if ((fraction() - l).numerator() <= 0)
                      return true; // duration fits in l
                }

          return false; // doesn't fit by changing dots alone (type needs to be changed too)
          }

    //---------------------------------------------------------
    //   operator -=
    //---------------------------------------------------------

    TDuration& TDuration::operator-=(const TDuration& t)
          {
          Fraction f1 = fraction() - t.fraction();
          TDuration d(f1);
          _val  = d._val;
          _dots = d._dots;
          return *this;
          }

    //---------------------------------------------------------
    //   operator +=
    //---------------------------------------------------------

    TDuration& TDuration::operator+=(const TDuration& t)
          {
          Fraction f1 = fraction() + t.fraction();
          TDuration d(f1);
          _val  = d._val;
          _dots = d._dots;
          return *this;
          }

    //---------------------------------------------------------
    //   toDurationList
    //---------------------------------------------------------

    std::vector<TDuration> toDurationList(Fraction l, bool useDots, int maxDots, bool printRestRemains)
          {
          std::vector<TDuration> dList;
          dList.reserve(8);

          if (!useDots)
                maxDots = 0;

          for (TDuration dd(l, true, maxDots); dd.isValid() && l.numerator() > 0; dd = TDuration(l, true, maxDots, dd.type())) {
                dList.push_back(dd);
                l -= dd.fraction();
                }

          if (printRestRemains && l.numerator() != 0)
                qDebug("toDurationList:: rest remains %d/%d", l.numerator(), l.denominator());

          return dList;
          }

    //---------------------------------------------------------
    //   toRhythmicDurationList
    //---------------------------------------------------------

    std::vector<TDuration> toRhythmicDurationList(const Fraction& l, bool isRest, int rtickStart, const TimeSigFrac& nominal, Measure* msr, int maxDots)
          {
          std::vector<TDuration> dList;
          dList.reserve(8);

          if (msr->isAnacrusis())
                rtickStart = nominal.ticksPerMeasure() - rtickStart;
          else if (isRest && l == msr->len()) {
                TDuration d = TDuration(TDuration::DurationType::V_MEASURE);
                dList.push_back(d);
                return dList;
                }

          if (nominal.isCompound())
                splitCompoundBeatsForList(&dList, l, isRest, rtickStart, nominal, maxDots);
          else
                populateRhythmicList(&dList, l, isRest, rtickStart, nominal, maxDots);

          return dList;
          }

    //---------------------------------------------------------
    //   populateRhythmicList
    //---------------------------------------------------------

    void populateRhythmicList(std::vector<TDuration>* dList, const Fraction& l, bool isRest, int rtickStart, const TimeSigFrac& nominal, int maxDots)
          {
          int rtickEnd = rtickStart + l.ticks();

          bool needToSplit = false; // do we need to split?
          int rtickSplit = 0; // tick to split on if we need to

          // CHECK AT SUBBEAT LEVEL

          int startLevel = nominal.rtick2subbeatLevel(rtickStart);
          int endLevel = nominal.rtick2subbeatLevel(rtickEnd);
          int strongestLevelCrossed = nominal.strongestSubbeatLevelInRange(rtickStart, rtickEnd, &rtickSplit); // sets rtickSplit

          if ((startLevel < 0) || (endLevel < 0) || (strongestLevelCrossed < 0)) {
                // Beyond maximum subbeat level so just split into largest possible durations.
                std::vector<TDuration> dList2 = toDurationList(l, maxDots > 0, maxDots, false);
                dList->insert(dList->end(), dList2.begin(), dList2.end());
                return;
                }

          // split if we cross something stronger than where we start and end
          if ((strongestLevelCrossed < startLevel) && (strongestLevelCrossed < endLevel))
                needToSplit = true;
          // but don't split for level 1 syncopation (allow eight-note, quarter, quarter... to cross unstressed beats)
          if (startLevel == endLevel && strongestLevelCrossed == startLevel - 1)
                needToSplit = false;
          // nor for the next simplest case of level 2 syncopation (allow sixteenth-note, eighth, eighth... to cross unstressed beats)
          if (startLevel == endLevel && strongestLevelCrossed == startLevel - 2) {
                // but disallow sixteenth-note, quarter, quarter...
                int ticksToNext = nominal.ticksToNextSubbeat(rtickStart, startLevel - 1);
                int ticksPastPrev = nominal.ticksPastSubbeat(rtickStart, startLevel - 1);
                needToSplit = ticksToNext != ticksPastPrev;
                }

          if (!needToSplit && strongestLevelCrossed == 0) {
                // NOW CHECK AT DENOMINATOR UNIT LEVEL AND BEAT LEVEL
                BeatType startBeat = nominal.rtick2beatType(rtickStart);
                BeatType endBeat = nominal.rtick2beatType(rtickEnd);

                int dUnitsCrossed = 0; // number of timeSig denominator units the note/rest crosses
                // if there is a choice of which beat to split on, should we use the first or last?
                bool useLast = startBeat <= BeatType::SIMPLE_UNSTRESSED; // split on the later beat if starting on a beat

                BeatType strongestBeatCrossed = nominal.strongestBeatInRange(rtickStart, rtickEnd, &dUnitsCrossed, &rtickSplit, useLast);

                needToSplit = forceRhythmicSplit(isRest, startBeat, endBeat, dUnitsCrossed, strongestBeatCrossed, nominal);
                }

          if (!needToSplit) {
                // CHECK THERE IS A DURATION THAT FITS
                // crossed beats/subbeats were not important so try to avoid splitting
                TDuration d = TDuration(l, true, maxDots);
                if (d.fraction() == l) {
                      // we can use a single duration - no need to split!
                      dList->push_back(l);
                      return;
                      }
                // no single TDuration fits so must split anyway
                }

          // Split on the strongest beat or subbeat crossed
          Fraction leftSplit = Fraction::fromTicks(rtickSplit  - rtickStart);
          Fraction rightSplit = l - leftSplit;

          // Recurse to see if we need to split further before adding to list
          populateRhythmicList(dList, leftSplit, isRest, rtickStart, nominal, maxDots);
          populateRhythmicList(dList, rightSplit, isRest, rtickSplit , nominal, maxDots);
          }

    //---------------------------------------------------------
    //   splitCompoundBeatsForList
    //    Split compound notes/rests where they enter a compound beat.
    //---------------------------------------------------------

    void splitCompoundBeatsForList(std::vector<TDuration>* dList, const Fraction& l, bool isRest, int rtickStart, const TimeSigFrac& nominal, int maxDots)
          {
          int rtickEnd = rtickStart + l.ticks();

          BeatType startBeat = nominal.rtick2beatType(rtickStart);
          BeatType endBeat = nominal.rtick2beatType(rtickEnd);

          if (startBeat > BeatType::COMPOUND_UNSTRESSED) {
                // Not starting on a compound beat so mustn't extend into next compound beat
                int splitTicks = nominal.ticksToNextBeat(rtickStart);

                if (rtickEnd - rtickStart > splitTicks) {
                      // Duration extends into next beat so must split
                      Fraction leftSplit = Fraction::fromTicks(splitTicks);
                      Fraction rightSplit = l - leftSplit;
                      populateRhythmicList(dList, leftSplit, isRest, rtickStart, nominal, maxDots); // this side is ok to proceed
                      splitCompoundBeatsForList(dList, rightSplit, isRest, rtickStart + splitTicks, nominal, maxDots); // not checked yet
                      return;
                      }
                }

          if (endBeat > BeatType::COMPOUND_UNSTRESSED) {
                // Not ending on a compound beat so mustn't extend into previous compound beat
                int splitTicks = nominal.ticksPastBeat(rtickEnd);

                if (rtickEnd - rtickStart > splitTicks) {
                      // Duration extends into previous beat so must split
                      Fraction rightSplit = Fraction::fromTicks(splitTicks);
                      Fraction leftSplit = l - rightSplit;
                      populateRhythmicList(dList, leftSplit, isRest, rtickStart, nominal, maxDots); // must add leftSplit to list first
                      populateRhythmicList(dList, rightSplit, isRest, rtickEnd - splitTicks, nominal, maxDots);
                      return;
                      }
                }

          // Duration either starts and ends on compound beats, or it remains within a single compound beat
          populateRhythmicList(dList, l, isRest, rtickStart, nominal, maxDots);
          }

    //---------------------------------------------------------
    //   forceRhythmicSplit
    //    Where to split notes and force a tie to indicate rhythm.
    //
    //    The function assumes the following:
    //      * Note/rest has already been split at measure boundaries.
    //      * Full measure rest was used if possible
    //      * Note/rest already split where it enters a compound beat.
    //
    //    Usage: Set crossedBeat to the strongest BeatType crossed by
    //    the note. Split note if function returns true. Repeat with
    //    the two new notes, and so on, until function returns false.
    //
    //    Note: If no single TDuration can fill the gap then the note
    //    *has* to be split, regardless of what this function returns.
    //    Non-rhythmic splits should still occur on the strongest beat.
    //
    //    Implementation: When comparing BeatTypes use <, <=, >, >=
    //    instead of == and != as appropriate (see sig.h). E.g. to match
    //    all full beats: "<= SIMPLE_UNSTRESSED". This will match for
    //    all compound and simple full beats, and not any subbeats.
    //---------------------------------------------------------

    bool forceRhythmicSplit(bool isRest, BeatType startBeat, BeatType endBeat, int dUnitsCrossed, BeatType strongestBeatCrossed, const TimeSigFrac& nominal) {
          // Assumption: Notes were split at measure boundary before this function was
          // called. (Necessary because timeSig might be different in next measure.)
          Q_ASSERT(strongestBeatCrossed != BeatType::DOWNBEAT);
          // Assumption: compound notes have already been split where they enter a compound beat.
          // (Necessary because the split beat is not always the strongest beat in this case.)
          Q_ASSERT(!nominal.isCompound() || strongestBeatCrossed >= BeatType::COMPOUND_SUBBEAT
                || (startBeat <= BeatType::COMPOUND_UNSTRESSED && endBeat <= BeatType::COMPOUND_UNSTRESSED));

          // SPECIAL CASES

          // nothing can cross a stressed beat in an irregular time signature
          if (strongestBeatCrossed <= BeatType::SIMPLE_STRESSED && !nominal.isTriple() && !nominal.isDuple())
                return true;
          if (isRest) {
                // rests must not cross the middle of a bar with numerator == 2 (e.g. 2/4 bar) even though the beat is unstressed
                if (strongestBeatCrossed <= BeatType::SIMPLE_UNSTRESSED && nominal.numerator() == 2)
                      return true;
                // rests must not cross a beat in a triple meter - simple (e.g. 3/4) or compound (e.g. 9/8)
                if (strongestBeatCrossed <= BeatType::SIMPLE_UNSTRESSED && nominal.isTriple())
                      return true;
                }

          // GENERAL RULES

          if (nominal.isCompound())
                return forceRhythmicSplitCompound(isRest, startBeat, endBeat, dUnitsCrossed, strongestBeatCrossed);
          else
                return forceRhythmicSplitSimple(isRest, startBeat, endBeat, dUnitsCrossed, strongestBeatCrossed);
          }

    //---------------------------------------------------------
    //   forceRhythmicSplitCompound
    //---------------------------------------------------------

    bool forceRhythmicSplitCompound(bool isRest, BeatType startBeat, BeatType endBeat, int dUnitsCrossed, BeatType strongestBeatCrossed)
          {
          switch (strongestBeatCrossed) {
                case BeatType::COMPOUND_STRESSED:
                      // Assumption: compound notes have already been split where they enter a compound beat.
                      Q_ASSERT(startBeat <= BeatType::COMPOUND_UNSTRESSED && endBeat <= BeatType::COMPOUND_UNSTRESSED);
                      // Notes are guaranteed to and start on a compound beat so we can pretend we have a simple measure.
                      return forceRhythmicSplitSimple(isRest, startBeat, endBeat, dUnitsCrossed / 3, BeatType::SIMPLE_STRESSED);
                case BeatType::COMPOUND_UNSTRESSED:
                      // Same assumption as before
                      Q_ASSERT(startBeat <= BeatType::COMPOUND_UNSTRESSED && endBeat <= BeatType::COMPOUND_UNSTRESSED);
                      // No further conditions since note are guaranteed to start and end on a compound beat.
                      return false;
                case BeatType::COMPOUND_SUBBEAT:
                      // don't split anything that takes up a full compound beat
                      if (startBeat <= BeatType::COMPOUND_UNSTRESSED && endBeat <= BeatType::COMPOUND_UNSTRESSED)
                            return false;
                      // split rests that don't start on a compound beat
                      if (isRest && startBeat > BeatType::COMPOUND_UNSTRESSED)
                            return true;
                      // Remaining groupings within compound triplets are the same as for simple triple (3/4, 3/8, etc.)
                      return forceRhythmicSplitSimple(isRest, startBeat, endBeat, dUnitsCrossed, BeatType::SIMPLE_UNSTRESSED);
                default: // BeatType::SUBBEAT
                      return forceRhythmicSplitSimple(isRest, startBeat, endBeat, dUnitsCrossed, strongestBeatCrossed);
                }
          }

    //---------------------------------------------------------
    //   forceRhythmicSplitSimple
    //    Implementation: This function is also called for compound
    //    measures so be careful when comparing BeatTypes. Use <, <=,
    //    >, >= instead of == and != when appropriate. (See sig.h)
    //---------------------------------------------------------

    bool forceRhythmicSplitSimple(bool isRest, BeatType startBeat, BeatType endBeat, int beatsCrossed, BeatType strongestBeatCrossed)
          {
          switch (strongestBeatCrossed) {
                case BeatType::SIMPLE_STRESSED:
                      // Must split rests on a stressed beat.
                      if (isRest)
                            return true;
                      // Don't split notes that start or end on a stressed beat. Enables double-dotting in 4/4.
                      // (Don't remove this to disable double-dotting, instead set maxDots = 1 elsewhere.)
                      if (startBeat <= BeatType::SIMPLE_STRESSED || endBeat <= BeatType::SIMPLE_STRESSED)
                            return false;
                      // Don't split notes that both start and end on unstressed beats or stronger.
                      if (startBeat <= BeatType::SIMPLE_UNSTRESSED && endBeat <= BeatType::SIMPLE_UNSTRESSED)
                            return false;
                      // anything else must split on stressed beat.
                      return true;
                case BeatType::SIMPLE_UNSTRESSED:
                      // Don't split notes or rests if starting and ending on stressed beat.
                      if (startBeat <= BeatType::SIMPLE_STRESSED && endBeat <= BeatType::SIMPLE_STRESSED)
                            return false;
                      // Split rests that don't start or end on a beat. Notes may cross 1 unstressed beat.
                      if (startBeat == BeatType::SUBBEAT || endBeat == BeatType::SUBBEAT)
                            return isRest || (beatsCrossed > 1);
                      return false;
                default: // BeatType::SUBBEAT
                      return false;
                }
          }

    //---------------------------------------------------------
    //   print
    //---------------------------------------------------------

    QString TDuration::durationTypeUserName() const
          {
          QString s = QObject::tr("Custom");
          switch(_val) {
                case DurationType::V_LONG:      s = QObject::tr("Longa"  ); break;
                case DurationType::V_BREVE:     s = QObject::tr("Breve"  ); break;
                case DurationType::V_WHOLE:     s = QObject::tr("Whole"  ); break;
                case DurationType::V_HALF:      s = QObject::tr("Half"   ); break;
                case DurationType::V_QUARTER:   s = QObject::tr("Quarter"); break;
                case DurationType::V_EIGHTH:    s = QObject::tr("Eighth" ); break;
                case DurationType::V_16TH:      s = QObject::tr("16th"   ); break;
                case DurationType::V_32ND:      s = QObject::tr("32nd"   ); break;
                case DurationType::V_64TH:      s = QObject::tr("64th"   ); break;
                case DurationType::V_128TH:     s = QObject::tr("128th"  ); break;
                case DurationType::V_256TH:     s = QObject::tr("256th"  ); break;
                case DurationType::V_512TH:     s = QObject::tr("512th"  ); break;
                case DurationType::V_1024TH:    s = QObject::tr("1024th" ); break;
                case DurationType::V_ZERO:      s = QObject::tr("Zero"   ); break;
                case DurationType::V_MEASURE:   s = QObject::tr("Measure"); break;
                case DurationType::V_INVALID:   s = QObject::tr("Invalid"); break;
                };
          return s;
          }

    //---------------------------------------------------------
    //   setType
    //---------------------------------------------------------

    void TDuration::setType(DurationType t)
          {
          _val = t;
          if (_val == DurationType::V_MEASURE)
                _dots = 0;
          }

    //---------------------------------------------------------
    //   isValid
    //---------------------------------------------------------

    bool TDuration::isValid(Fraction f)
         {
         TDuration t;
         t.setType(DurationType::V_LONG);
         t.setDots(4);
         t.truncateToFraction(f, 4);
         return ((t.fraction() - f).numerator() == 0);
         }
    }

↑ V793 It is odd that the result of the 'ticks / t' statement is a part of the condition. Perhaps, this statement should have been compared with something else.