LCOV - code coverage report
Current view: top level - src/engraving/dom - sig.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 62.9 % 210 132
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "sig.h"
      24              : 
      25              : #include "log.h"
      26              : 
      27              : using namespace mu;
      28              : 
      29              : namespace mu::engraving {
      30              : //---------------------------------------------------------
      31              : //   ticks_beat
      32              : //---------------------------------------------------------
      33              : 
      34         6505 : int ticks_beat(int n)
      35              : {
      36         6505 :     int m = (Constants::DIVISION * 4) / n;
      37         6505 :     if ((Constants::DIVISION* 4) % n) {
      38            0 :         ASSERT_X(String(u"Mscore: ticks_beat(): bad divisor %1").arg(n));
      39              :     }
      40         6505 :     return m;
      41              : }
      42              : 
      43              : //---------------------------------------------------------
      44              : //   ticks_measure
      45              : //---------------------------------------------------------
      46              : 
      47        11995 : static int ticks_measure(const Fraction& f)
      48              : {
      49        11995 :     return (Constants::DIVISION * 4 * f.numerator()) / f.denominator();
      50              : }
      51              : 
      52              : //---------------------------------------------------------
      53              : //   rtick2beatType
      54              : //    caller must adjust rtick as appropriate if the measure's
      55              : //    actual timeSig is different from the nominal timeSig.
      56              : //---------------------------------------------------------
      57              : 
      58         4760 : BeatType TimeSigFrac::rtick2beatType(int rtick) const
      59              : {
      60         4760 :     if (rtick == 0) {
      61          379 :         return BeatType::DOWNBEAT;     // note: only return DOWNBEAT for rtick = 0, not for rtick = measureTicks,
      62              :     }
      63         4381 :     if (rtick % dUnitTicks() != 0) {
      64          605 :         return BeatType::SUBBEAT;
      65              :     }
      66              : 
      67         3776 :     if (isCompound()) {
      68         1115 :         if (rtick % beatTicks() != 0) {
      69          645 :             return BeatType::COMPOUND_SUBBEAT;
      70              :         }
      71              :     }
      72              : 
      73         3131 :     const int beatNum = rtick / beatTicks();
      74              : 
      75         3131 :     int stressBeat = 0;
      76              : 
      77         3131 :     if (isTriple()) {
      78          256 :         stressBeat = 3;
      79         2875 :     } else if (isDuple()) {
      80         2631 :         stressBeat = 2;
      81              :     } else {
      82          244 :         stressBeat = (numerator() + 1) / 2;     // Assumes 5/4 timeSig = (3+2)/4. (The same assumption is used for beaming)
      83              :     }
      84         3131 :     if (stressBeat && beatNum % stressBeat == 0) {
      85         1414 :         return isCompound() ? BeatType::COMPOUND_STRESSED : BeatType::SIMPLE_STRESSED;
      86              :     }
      87              : 
      88         1717 :     return isCompound() ? BeatType::COMPOUND_UNSTRESSED : BeatType::SIMPLE_UNSTRESSED;
      89              : }
      90              : 
      91              : //---------------------------------------------------------
      92              : //   strongestBeatInRange
      93              : //    dUnitsCrossed - pointer to store number crossed
      94              : //    subbeatTick - pointer to store tick of strongest beat
      95              : //    saveLast - which tick to store if strongest type is
      96              : //                crossed more than once
      97              : //
      98              : //    caller must adjust rticks as appropriate if the measure's
      99              : //    actual timeSig is different from the nominal timeSig.
     100              : //---------------------------------------------------------
     101              : 
     102         1042 : BeatType TimeSigFrac::strongestBeatInRange(int rtick1, int rtick2, int* dUnitsCrossed, int* subbeatTick, bool saveLast) const
     103              : {
     104         1042 :     assert(rtick2 > rtick1);
     105              : 
     106         1042 :     BeatType strongest = BeatType::SUBBEAT;
     107              : 
     108         2585 :     for (int rtick = rtick1 + ticksToNextDUnit(rtick1); rtick < rtick2; rtick += dUnitTicks()) {
     109         1543 :         if (dUnitsCrossed) {
     110         1543 :             (*dUnitsCrossed)++;
     111              :         }
     112         1543 :         BeatType type = rtick2beatType(rtick);
     113         1543 :         if (static_cast<int>(type) < static_cast<int>(strongest) + saveLast) {     // "<" behaves like "<=" if saveLast is true
     114         1274 :             strongest = type;
     115         1274 :             if (subbeatTick) {
     116         1274 :                 (*subbeatTick) = rtick;
     117              :             }
     118              :         }
     119              :     }
     120              : 
     121         1042 :     return strongest;
     122              : }
     123              : 
     124              : //---------------------------------------------------------
     125              : //   subbeatTicks
     126              : //    divides dUnitTicks() by 2 once for each level.
     127              : //---------------------------------------------------------
     128              : 
     129          192 : int TimeSigFrac::subbeatTicks(int level) const
     130              : {
     131          192 :     assert(level <= maxSubbeatLevel());
     132          192 :     int subbeatTicks = dUnitTicks();
     133          402 :     while (level > 0) {
     134          210 :         subbeatTicks /= 2;
     135          210 :         level--;
     136              :     }
     137          192 :     return subbeatTicks;
     138              : }
     139              : 
     140              : //---------------------------------------------------------
     141              : //   maxSubbeatLevel
     142              : //    subdivision beyond this level would result in rounding errors
     143              : //---------------------------------------------------------
     144              : 
     145          192 : int TimeSigFrac::maxSubbeatLevel() const
     146              : {
     147          192 :     int level = 0;
     148          192 :     int subbeatTicks = dUnitTicks();
     149         1152 :     while (subbeatTicks % 2 == 0) {
     150          960 :         subbeatTicks /= 2;
     151          960 :         level++;
     152              :     }
     153          192 :     return level;
     154              : }
     155              : 
     156              : //---------------------------------------------------------
     157              : //   rtick2subbeatLevel
     158              : //    returns 0 if rtick is on a beat or denominator unit.
     159              : //    returns 1 if rtick lies halfway between dUnits
     160              : //    returns 2 if rtick lies on a multiple of  1/4  of dUnit
     161              : //            3                                 1/8
     162              : //            4                                 1/16
     163              : //            n                                 1/(2**n)
     164              : //    returns -(n+1) if max n is reached and rtick still not found.
     165              : //
     166              : //    Caller must adjust rtick as appropriate if the measure's
     167              : //    actual timeSig is different from the nominal timeSig.
     168              : //---------------------------------------------------------
     169              : 
     170         5066 : int TimeSigFrac::rtick2subbeatLevel(int rtick) const
     171              : {
     172         5066 :     int level = 0;
     173         5066 :     int subbeatTicks = dUnitTicks();
     174         5066 :     int remainder = rtick % subbeatTicks;
     175         7429 :     while (remainder != 0) {
     176         2366 :         level++;
     177         2366 :         if (subbeatTicks % 2 != 0) {
     178            3 :             return -level;       // further sub-division would split measure into chunks of unequal length.
     179              :         }
     180         2363 :         subbeatTicks /= 2;
     181         2363 :         remainder %= subbeatTicks;
     182              :     }
     183         5063 :     return level;
     184              : }
     185              : 
     186              : //---------------------------------------------------------
     187              : //   strongestSubbeatLevelInRange
     188              : //    Return value is negative if none are found.
     189              : //
     190              : //    Caller must adjust rtick as appropriate if the measure's
     191              : //    actual timeSig is different from the nominal timeSig.
     192              : //---------------------------------------------------------
     193              : 
     194         2533 : int TimeSigFrac::strongestSubbeatLevelInRange(int rtick1, int rtick2, int* subbeatTick) const
     195              : {
     196         2533 :     assert(rtick2 > rtick1);
     197              : 
     198         2533 :     for (int level = 0, subbeatTicks = dUnitTicks();;) {
     199         5045 :         int n = rtick1 / subbeatTicks;
     200         5045 :         int m = (rtick2 - 1) / subbeatTicks;     // -1 to make the range exclusive
     201         5045 :         if (m > n) {
     202         2522 :             if (subbeatTick) {
     203         2522 :                 (*subbeatTick) = m * subbeatTicks;
     204              :             }
     205         2522 :             return level;
     206              :         }
     207         2523 :         level++;
     208         2523 :         if (subbeatTicks % 2 != 0) {
     209           11 :             return -level;       // further sub-division would split measure into chunks of unequal length.
     210              :         }
     211         2512 :         subbeatTicks /= 2;
     212         2512 :     }
     213              : }
     214              : 
     215              : //---------------------------------------------------------
     216              : //   operator==
     217              : //---------------------------------------------------------
     218              : 
     219           27 : bool SigEvent::operator==(const SigEvent& e) const
     220              : {
     221           27 :     return m_timesig.identical(e.m_timesig);
     222              : }
     223              : 
     224              : //---------------------------------------------------------
     225              : //   add
     226              : //---------------------------------------------------------
     227              : 
     228              : const TimeSigFrac TimeSigMap::DEFAULT_TIME_SIGNATURE(4, 4);
     229              : 
     230         2904 : void TimeSigMap::add(int tick, const Fraction& f)
     231              : {
     232         2904 :     if (!f.isValid()) {
     233            0 :         LOGD("illegal signature %d/%d", f.numerator(), f.denominator());
     234              :     }
     235         2904 :     (*this)[tick] = SigEvent(f);
     236         2904 :     normalize();
     237         2904 : }
     238              : 
     239         2693 : void TimeSigMap::add(int tick, const SigEvent& ev)
     240              : {
     241         2693 :     (*this)[tick] = ev;
     242         2693 :     normalize();
     243         2693 : }
     244              : 
     245              : //---------------------------------------------------------
     246              : //   del
     247              : //---------------------------------------------------------
     248              : 
     249            0 : void TimeSigMap::del(int tick)
     250              : {
     251            0 :     erase(tick);
     252            0 :     normalize();
     253            0 : }
     254              : 
     255              : //---------------------------------------------------------
     256              : //   clearRange
     257              : //    Clears the given range, start tick included, end tick
     258              : //    excluded.
     259              : //---------------------------------------------------------
     260              : 
     261            0 : void TimeSigMap::clearRange(int tick1, int tick2)
     262              : {
     263            0 :     iterator first = lower_bound(tick1);
     264            0 :     iterator last = lower_bound(tick2);
     265            0 :     if (first == last) {
     266            0 :         return;
     267              :     }
     268            0 :     erase(first, last);
     269            0 :     normalize();
     270              : }
     271              : 
     272              : //---------------------------------------------------------
     273              : //   TimeSigMap::normalize
     274              : //---------------------------------------------------------
     275              : 
     276         5623 : void TimeSigMap::normalize()
     277              : {
     278         5623 :     int z    = 4;
     279         5623 :     int n    = 4;
     280         5623 :     int tick = 0;
     281         5623 :     TimeSigFrac bar;
     282         5623 :     int tm   = ticks_measure(TimeSigFrac(z, n));
     283              : 
     284        11995 :     for (auto i = begin(); i != end(); ++i) {
     285         6372 :         SigEvent& e  = i->second;
     286         6372 :         bar += TimeSigFrac(i->first - tick, tm).reduced();
     287         6372 :         e.setBar(bar.numerator() / bar.denominator());
     288         6372 :         tick = i->first;
     289         6372 :         tm   = ticks_measure(e.timesig());
     290              :     }
     291         5623 : }
     292              : 
     293              : //---------------------------------------------------------
     294              : //   timesig
     295              : //---------------------------------------------------------
     296              : 
     297         6443 : const SigEvent& TimeSigMap::timesig(int tick) const
     298              : {
     299         6443 :     static const SigEvent ev(DEFAULT_TIME_SIGNATURE);
     300         6443 :     if (empty()) {
     301           86 :         return ev;
     302              :     }
     303         6357 :     auto i = upper_bound(tick);
     304         6357 :     if (i != begin()) {
     305         6357 :         --i;
     306              :     }
     307         6357 :     return i->second;
     308              : }
     309              : 
     310              : //---------------------------------------------------------
     311              : //   tickValues
     312              : //    t - some time moment on timeline (in ticks)
     313              : //
     314              : //    Result - values computed for this time moment:
     315              : //    bar - index of bar containing time moment t
     316              : //    beat - index of beat in bar containing t
     317              : //    tick - position of t in beat (in ticks)
     318              : //---------------------------------------------------------
     319              : 
     320         1827 : void TimeSigMap::tickValues(int t, int* bar, int* beat, int* tick) const
     321              : {
     322         1827 :     if (empty()) {
     323            0 :         *bar  = 0;
     324            0 :         *beat = 0;
     325            0 :         *tick = 0;
     326            0 :         return;
     327              :     }
     328         1827 :     auto e = upper_bound(t);
     329         1827 :     IF_ASSERT_FAILED_X(e != begin(), String(u"tickValue(0x%1) not found").arg(t)) {
     330            0 :         *bar  = 0;
     331            0 :         *beat = 0;
     332            0 :         *tick = 0;
     333            0 :         return;
     334              :     }
     335         1827 :     --e;
     336         1827 :     int delta  = t - e->first;
     337         1827 :     int ticksB = ticks_beat(e->second.timesig().denominator());   // ticks in beat
     338         1827 :     int ticksM = ticksB * e->second.timesig().numerator();        // ticks in measure (bar)
     339         1827 :     if (ticksM == 0) {
     340            0 :         LOGD("TimeSigMap::tickValues: at %d %s", t, muPrintable(e->second.timesig().toString()));
     341            0 :         *bar  = 0;
     342            0 :         *beat = 0;
     343            0 :         *tick = 0;
     344            0 :         return;
     345              :     }
     346         1827 :     *bar       = e->second.bar() + delta / ticksM;
     347         1827 :     int rest   = delta % ticksM;
     348         1827 :     *beat      = rest / ticksB;
     349         1827 :     *tick      = rest % ticksB;
     350              : }
     351              : 
     352              : //---------------------------------------------------------
     353              : //   pos
     354              : //    Return string representation of tick position.
     355              : //    This is not reentrant and only for debugging!
     356              : //---------------------------------------------------------
     357              : 
     358            0 : String TimeSigMap::pos(int t) const
     359              : {
     360              :     int bar, beat, tick;
     361            0 :     tickValues(t, &bar, &beat, &tick);
     362            0 :     return String(u"%1:%2:%3").arg(bar + 1, beat, tick);
     363              : }
     364              : 
     365              : //---------------------------------------------------------
     366              : //   bar2tick
     367              : //    Returns the absolute start time (in ticks)
     368              : //    of beat in bar
     369              : //---------------------------------------------------------
     370              : 
     371         4603 : int TimeSigMap::bar2tick(int bar, int beat) const
     372              : {
     373              :     // bar - index of current bar (terminology: bar == measure)
     374              :     // beat - index of beat in current bar
     375         4603 :     auto e = begin();
     376              : 
     377         9382 :     for (; e != end(); ++e) {
     378         4858 :         if (bar < e->second.bar()) {
     379           79 :             break;
     380              :         }
     381              :     }
     382         4603 :     if (empty() || e == begin()) {
     383            0 :         LOGD("TimeSigMap::bar2tick(): not found(%d,%d) not found", bar, beat);
     384            0 :         if (empty()) {
     385            0 :             LOGD("   list is empty");
     386              :         }
     387            0 :         return 0;
     388              :     }
     389         4603 :     --e;   // current TimeSigMap value
     390         4603 :     int ticksB = ticks_beat(e->second.timesig().denominator());   // ticks per beat
     391         4603 :     int ticksM = ticksB * e->second.timesig().numerator();        // bar length in ticks
     392         4603 :     return e->first + (bar - e->second.bar()) * ticksM + ticksB * beat;
     393              : }
     394              : 
     395              : //---------------------------------------------------------
     396              : //   ticksPerMeasure
     397              : //---------------------------------------------------------
     398              : 
     399            0 : int ticksPerMeasure(int numerator, int denominator)
     400              : {
     401            0 :     return ticks_beat(denominator) * numerator;
     402              : }
     403              : 
     404              : //---------------------------------------------------------
     405              : //   rasterEval
     406              : //---------------------------------------------------------
     407              : 
     408            0 : unsigned rasterEval(unsigned t, int raster, int startTick,
     409              :                     int numerator, int denominator, int addition)
     410              : {
     411            0 :     int delta  = t - startTick;
     412            0 :     int ticksM = ticksPerMeasure(numerator, denominator);
     413            0 :     if (raster == 0) {
     414            0 :         raster = ticksM;
     415              :     }
     416            0 :     int rest   = delta % ticksM;
     417            0 :     int bb     = (delta / ticksM) * ticksM;
     418            0 :     return startTick + bb + ((rest + addition) / raster) * raster;
     419              : }
     420              : 
     421              : //---------------------------------------------------------
     422              : //   raster
     423              : //---------------------------------------------------------
     424              : 
     425            0 : unsigned TimeSigMap::raster(unsigned t, int raster) const
     426              : {
     427            0 :     if (raster == 1) {
     428            0 :         return t;
     429              :     }
     430            0 :     auto e = upper_bound(t);
     431            0 :     if (e == end()) {
     432            0 :         LOGD("TimeSigMap::raster(%x,)", t);
     433            0 :         return t;
     434              :     }
     435            0 :     auto timesig = e->second.timesig();
     436            0 :     return rasterEval(t, raster, e->first, timesig.numerator(),
     437            0 :                       timesig.denominator(), raster / 2);
     438              : }
     439              : 
     440              : //---------------------------------------------------------
     441              : //   raster1
     442              : //    round down
     443              : //---------------------------------------------------------
     444              : 
     445            0 : unsigned TimeSigMap::raster1(unsigned t, int raster) const
     446              : {
     447            0 :     if (raster == 1) {
     448            0 :         return t;
     449              :     }
     450            0 :     auto e = upper_bound(t);
     451            0 :     auto timesig = e->second.timesig();
     452            0 :     return rasterEval(t, raster, e->first, timesig.numerator(),
     453            0 :                       timesig.denominator(), 0);
     454              : }
     455              : 
     456              : //---------------------------------------------------------
     457              : //   raster2
     458              : //    round up
     459              : //---------------------------------------------------------
     460              : 
     461            0 : unsigned TimeSigMap::raster2(unsigned t, int raster) const
     462              : {
     463            0 :     if (raster == 1) {
     464            0 :         return t;
     465              :     }
     466            0 :     auto e = upper_bound(t);
     467            0 :     auto timesig = e->second.timesig();
     468            0 :     return rasterEval(t, raster, e->first, timesig.numerator(),
     469            0 :                       timesig.denominator(), raster - 1);
     470              : }
     471              : 
     472              : //---------------------------------------------------------
     473              : //   rasterStep
     474              : //---------------------------------------------------------
     475              : 
     476            0 : int TimeSigMap::rasterStep(unsigned t, int raster) const
     477              : {
     478            0 :     if (raster == 0) {
     479            0 :         auto timesig = upper_bound(t)->second.timesig();
     480            0 :         return ticksPerMeasure(timesig.denominator(), timesig.numerator());
     481              :     }
     482            0 :     return raster;
     483              : }
     484              : 
     485              : //---------------------------------------------------------
     486              : //   TimeSigMap::dump
     487              : //---------------------------------------------------------
     488              : 
     489            0 : void TimeSigMap::dump() const
     490              : {
     491            0 :     LOGD("TimeSigMap:");
     492            0 :     for (auto i = begin(); i != end(); ++i) {
     493            0 :         LOGD("%6d timesig: %s measure: %d",
     494            0 :              i->first, muPrintable(i->second.timesig().toString()), i->second.bar());
     495              :     }
     496            0 : }
     497              : 
     498              : //---------------------------------------------------------
     499              : //   dUnitTicks
     500              : //---------------------------------------------------------
     501              : 
     502        20714 : int TimeSigFrac::dUnitTicks() const
     503              : {
     504        20714 :     return (4 * Constants::DIVISION) / denominator();
     505              : }
     506              : }
        

Generated by: LCOV version 2.0-1