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