1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2002-2009 Werner Schweer
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 #ifndef __AL_SIG_H__
14 #define __AL_SIG_H__
15 
16 #include "fraction.h"
17 
18 namespace Ms {
19 
20 class XmlWriter;
21 class XmlReader;
22 
23 int ticks_beat(int n);
24 
25 //-------------------------------------------------------------------
26 //   BeatType
27 //-------------------------------------------------------------------
28 
29 enum class BeatType : char {
30       DOWNBEAT,               // 1st beat of measure (rtick == 0)
31       COMPOUND_STRESSED,      // e.g. eighth-note number 7 in 12/8
32       SIMPLE_STRESSED,        // e.g. beat 3 in 4/4
33       COMPOUND_UNSTRESSED,    // e.g. eighth-note numbers 4 or 10 in 12/8
34       SIMPLE_UNSTRESSED,      // "offbeat" e.g. beat 2 and 4 in 4/4 (i.e. the denominator unit)
35       COMPOUND_SUBBEAT,       // e.g. any other eighth-note in 12/8 (i.e. the denominator unit)
36       SUBBEAT                 // does not fall on a beat
37       };
38 
39 //-------------------------------------------------------------------
40 //   Time Signature Fraction   (n/d - numerator/denominator)
41 //-------------------------------------------------------------------
42 
43 class TimeSigFrac : public Fraction {
44 
45    public:
46       using Fraction::Fraction;
Fraction(n,d)47       constexpr TimeSigFrac(int n = 0, int d = 1) : Fraction(n, d) {}
TimeSigFrac(const Fraction & f)48       TimeSigFrac(const Fraction& f) : TimeSigFrac(f.numerator(), f.denominator()) {}
TimeSigFrac(const TimeSigFrac & f)49       TimeSigFrac(const TimeSigFrac& f) : TimeSigFrac(f.numerator(), f.denominator()) {}
50 
51       // isCompound? Note: 3/8, 3/16, ... are NOT considered compound.
isCompound()52       bool isCompound() const { return numerator() > 3 /*&& denominator() >= 8*/ && numerator() % 3 == 0; }
53 
54       // isBeatedCompound? Note: Conductors will beat the simple unit at slow tempos (<60 compound units per minute)
55       // However, the meter is still considered to be compound (at least for our purposes).
isBeatedCompound(qreal tempo)56       bool isBeatedCompound(qreal tempo) const { return tempo2beatsPerMinute(tempo) >= 60.0; }
57 
58       int dUnitTicks()        const;
ticksPerMeasure()59       int ticksPerMeasure()   const   { return numerator() * dUnitTicks(); }
60 
dUnitsPerBeat()61       int dUnitsPerBeat()     const   { return isCompound() ? 3 : 1; }
beatTicks()62       int beatTicks()         const   { return dUnitTicks() * dUnitsPerBeat(); }
beatsPerMeasure()63       int beatsPerMeasure()   const   { return numerator() / dUnitsPerBeat(); }
64 
65       int subbeatTicks(int level)   const;
66       int maxSubbeatLevel()         const;
67 
isTriple()68       bool isTriple()         const   { return beatsPerMeasure() % 3 == 0; }
isDuple()69       bool isDuple() const { Q_ASSERT(!isTriple()); return beatsPerMeasure() % 2 == 0; } // note: always test isTriple() first
70 
71       // MuseScore stores tempos in quarter-notes-per-second, so conversions to conventional beats-per-minute format are provided here:
tempo2beatsPerMinute(qreal tempo)72       qreal tempo2beatsPerMinute(qreal tempo)   const { return tempo * denominator() * 15.0 / dUnitsPerBeat(); }
beatsPerMinute2tempo(qreal bpm)73       qreal beatsPerMinute2tempo(qreal bpm)     const { return bpm * dUnitsPerBeat() / (15.0 * denominator()); }
74 
75       BeatType rtick2beatType(int rtick)  const;
76       int rtick2subbeatLevel(int rtick)   const; // returns negative value if not on a well-defined subbeat
77 
78       BeatType strongestBeatInRange(int rtick1, int rtick2, int* dUnitsCrossed = 0, int* subbeatTick = 0, bool saveLast = false) const; // range is exclusive
79       int strongestSubbeatLevelInRange(int rtick1, int rtick2, int* subbeatTick = 0) const; // range is exclusive
80 
ticksPastDUnit(int rtick)81       int ticksPastDUnit(int rtick)       const { return rtick % dUnitTicks(); }                 // returns 0 if rtick is exactly on a dUnit
ticksToNextDUnit(int rtick)82       int ticksToNextDUnit(int rtick)     const { return dUnitTicks() - ticksPastDUnit(rtick); } // returns dUnitTicks() if rtick is on a dUnit
83 
ticksPastBeat(int rtick)84       int ticksPastBeat(int rtick)        const { return rtick % beatTicks(); }                  // returns 0 if rtick is exactly on a beat
ticksToNextBeat(int rtick)85       int ticksToNextBeat(int rtick)      const { return beatTicks() - ticksPastBeat(rtick); }   // returns beatTicks() if rtick is on a beat
86 
ticksPastSubbeat(int rtick,int level)87       int ticksPastSubbeat(int rtick, int level)      const { return rtick % subbeatTicks(level); }
ticksToNextSubbeat(int rtick,int level)88       int ticksToNextSubbeat(int rtick, int level)    const { return subbeatTicks(level) - ticksPastSubbeat(rtick, level); }
89       };
90 
91 //-------------------------------------------------------------------
92 //   Time Signature Event
93 //    Incomplete measures as for example pickup measures have
94 //    a nominal duration different from actual duration.
95 //-------------------------------------------------------------------
96 
97 class SigEvent {
98       TimeSigFrac _timesig;
99       TimeSigFrac _nominal;
100       int _bar;               ///< precomputed value
101 
102    public:
103       int read(XmlReader&, int fileDivision);
104       void write(XmlWriter&, int) const;
105 
SigEvent()106       constexpr SigEvent() : _bar(0) {}       ///< default SigEvent is invalid
107       SigEvent(const Fraction& s, int bar = 0)
_timesig(s)108          : _timesig(s), _nominal(s), _bar(bar) {}
109       SigEvent(const Fraction& s, const Fraction& ss, int bar = 0)
_timesig(s)110          : _timesig(s), _nominal(ss), _bar(bar) {}
111       SigEvent(const SigEvent& e);
112 
113       bool operator==(const SigEvent& e) const;
valid()114       bool valid() const       { return _timesig.isValid(); }
print()115       QString print() const    { return _timesig.print();  }
timesig()116       TimeSigFrac timesig() const { return _timesig;          }
nominal()117       TimeSigFrac nominal() const { return _nominal;          }
setNominal(const Fraction & f)118       void setNominal(const Fraction& f) { _nominal = f;  }
bar()119       int bar() const          { return _bar;              }
setBar(int val)120       void setBar(int val)     { _bar = val;               }
121       };
122 
123 //---------------------------------------------------------
124 //   SigList
125 //---------------------------------------------------------
126 
127 class TimeSigMap : public std::map<int, SigEvent > {
128       void normalize();
129 
130    public:
TimeSigMap()131       TimeSigMap() {}
132 
133       void add(int tick, const Fraction&);
134       void add(int tick, const SigEvent& ev);
135 
136       void del(int tick);
137 
138       void clearRange(int tick1, int tick2);
139 
140       void read(XmlReader&, int fileDiv);
141       void write(XmlWriter&) const;
142       void dump() const;
143 
144       const SigEvent& timesig(int tick) const;
timesig(const Fraction & f)145       const SigEvent& timesig(const Fraction& f) const { return timesig(f.ticks()); }
146 
147       void tickValues(int t, int* bar, int* beat, int* tick) const;
148       int bar2tick(int bar, int beat) const;
149       QString pos(int t) const;
150 
151       unsigned raster(unsigned tick, int raster) const;
152       unsigned raster1(unsigned tick, int raster) const;    // round down
153       unsigned raster2(unsigned tick, int raster) const;    // round up
154       int rasterStep(unsigned tick, int raster) const;
155       };
156 
157 }     // namespace Ms
158 #endif
159