1 //========================================================= 2 // MusE 3 // Linux Music Editor 4 // $Id: tempo.h,v 1.2.2.1 2006/09/19 19:07:09 spamatica Exp $ 5 // 6 // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) 7 // 8 // This program is free software; you can redistribute it and/or 9 // modify it under the terms of the GNU General Public License 10 // as published by the Free Software Foundation; version 2 of 11 // the License, or (at your option) any later version. 12 // 13 // This program is distributed in the hope that it will be useful, 14 // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 // GNU General Public License for more details. 17 // 18 // You should have received a copy of the GNU General Public License 19 // along with this program; if not, write to the Free Software 20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 // 22 //========================================================= 23 24 #ifndef __TEMPO_H__ 25 #define __TEMPO_H__ 26 27 #include <map> 28 #include <vector> 29 30 #include "large_int.h" 31 32 #ifndef MAX_TICK 33 #define MAX_TICK (0x7fffffff/100) 34 #endif 35 36 // Tempo ring buffer size 37 #define TEMPO_FIFO_SIZE 1024 38 39 40 namespace MusECore { 41 42 class Xml; 43 44 //--------------------------------------------------------- 45 // Tempo Event 46 //--------------------------------------------------------- 47 48 struct TEvent { 49 int tempo; 50 unsigned tick; // new tempo at tick 51 unsigned frame; // precomputed time for tick in sec 52 53 int read(Xml&); 54 void write(int, Xml&, int) const; 55 TEventTEvent56 TEvent() { } TEventTEvent57 TEvent(unsigned t, unsigned tk) { 58 tempo = t; 59 tick = tk; 60 frame = 0; 61 } 62 }; 63 64 //--------------------------------------------------------- 65 // TempoList 66 //--------------------------------------------------------- 67 68 typedef std::map<unsigned, TEvent*, std::less<unsigned> > TEMPOLIST; 69 typedef TEMPOLIST::iterator iTEvent; 70 typedef TEMPOLIST::const_iterator ciTEvent; 71 typedef TEMPOLIST::reverse_iterator riTEvent; 72 typedef TEMPOLIST::const_reverse_iterator criTEvent; 73 74 class TempoList : public TEMPOLIST { 75 76 friend struct PendingOperationItem; 77 78 int _tempoSN; // serial no to track tempo changes 79 bool useList; 80 int _tempo; // tempo if not using tempo list 81 int _globalTempo; // %percent 50-200% 82 83 void add(unsigned tick, int tempo, bool do_normalize = true); 84 void add(unsigned tick, TEvent* e, bool do_normalize = true); 85 void del(iTEvent, bool do_normalize = true); 86 void del(unsigned tick, bool do_normalize = true); 87 88 public: 89 TempoList(); 90 ~TempoList(); 91 92 // Makes a copy of the source list including all allocated items. 93 // This clears and deletes existing items in the destination list. 94 void copy(const TempoList& src); 95 96 void normalize(); 97 void clear(); 98 void eraseRange(unsigned stick, unsigned etick); 99 100 void read(Xml&); 101 void write(int, Xml&) const; 102 void dump() const; 103 104 // Returns the actual Beats Per Minute at given tick or the static tempo value if master (useList) is off. 105 float bpm(unsigned tick) const; 106 // Bypass the master (useList) flag and return the actual Beats Per Minute at the given tick. 107 float bpmAt(unsigned tick) const; 108 // Returns a tempo value from the list at the given tick if master (useList) is on, or else the static tempo value. 109 // This is not in the same units as BPM. 110 int tempo(unsigned tick) const; 111 // Bypass the master (useList) flag and return a tempo value directly from the list at the given tick. 112 // This is not in the same units as BPM. 113 int tempoAt(unsigned tick) const; 114 115 116 //------------------------------------------------------------------------------------------------------- 117 // Normally do not round these tick to frame methods down since (audio) frame resolution is higher than tick 118 // resolution. Other rounding methods are provided for convenience, since tick to frame is a 'broad' question. 119 //------------------------------------------------------------------------------------------------------- 120 // Returns the number of frames contained in the given ticks, 121 // at the tempo at the tick given by tempoTick. Honours useList. 122 unsigned ticks2frames(unsigned ticks, unsigned tempoTick, LargeIntRoundMode round_mode = LargeIntRoundUp) const; 123 // TODO 124 // // Returns the number of ticks contained in the given frames, 125 // // at the tempo at the tick given by tempoTick. Honours useList. 126 // unsigned frames2ticks(unsigned frames, unsigned tempoTick) const; 127 unsigned tick2frame(unsigned tick, unsigned frame, int* sn, LargeIntRoundMode round_mode = LargeIntRoundUp) const; 128 unsigned tick2frame(unsigned tick, int* sn = 0, LargeIntRoundMode round_mode = LargeIntRoundUp) const; 129 unsigned deltaTick2frame(unsigned tick1, unsigned tick2, int* sn = 0, LargeIntRoundMode round_mode = LargeIntRoundUp) const; 130 131 //------------------------------------------------------------------------------------------------------- 132 // Normally do not round these frame to tick methods up since (audio) frame resolution is higher than tick 133 // resolution. Other rounding methods are provided for convenience, since frame to tick is a 'broad' question. 134 // Only round up or to nearest if you know what you are doing. It is OK to do that for example 135 // to VISUALLY 'snap' the frame to a tick from either side of the tick (the MTScale time scale widgets). 136 // But for most other uses especially timing, leave it alone at rounding down. Timing ticks need to change 137 // to the next value ONLY when there are enough frames to count as one whole tick. Otherwise tick-based 138 // events such as midi notes might be processed slightly too soon (or too late in some circumstances). 139 //------------------------------------------------------------------------------------------------------- 140 unsigned frame2tick(unsigned frame, int* sn = 0, LargeIntRoundMode round_mode = LargeIntRoundDown) const; 141 unsigned frame2tick(unsigned frame, unsigned tick, int* sn, LargeIntRoundMode round_mode = LargeIntRoundDown) const; 142 unsigned deltaFrame2tick(unsigned frame1, unsigned frame2, int* sn = 0, LargeIntRoundMode round_mode = LargeIntRoundDown) const; 143 tempoSN()144 int tempoSN() const { return _tempoSN; } 145 // Sets the tempo value in the list if master is on, or else the static tempo value. 146 void setTempo(unsigned tick, int newTempo); 147 // Returns the static tempo value (the one used when the master is off). staticTempo()148 int staticTempo() const { return _tempo; } 149 // Sets the static tempo value (the one used when the master is off). 150 void setStaticTempo(int newTempo); 151 void addTempo(unsigned t, int tempo, bool do_normalize = true); 152 void delTempo(unsigned tick, bool do_normalize = true); masterFlag()153 bool masterFlag() const { return useList; } 154 bool setMasterFlag(unsigned tick, bool val); globalTempo()155 int globalTempo() const { return _globalTempo; } 156 void setGlobalTempo(int val); 157 }; 158 159 //--------------------------------------------------------- 160 // Tempo Record Event 161 //--------------------------------------------------------- 162 163 struct TempoRecEvent { 164 int tempo; 165 unsigned tick; TempoRecEventTempoRecEvent166 TempoRecEvent() { } TempoRecEventTempoRecEvent167 TempoRecEvent(unsigned tk, unsigned t) { 168 tick = tk; 169 tempo = t; 170 } 171 }; 172 173 class TempoRecList : public std::vector<TempoRecEvent > 174 { 175 public: addTempo(int tick,int tempo)176 void addTempo(int tick, int tempo) { push_back(TempoRecEvent(tick, tempo)); } addTempo(const TempoRecEvent & e)177 void addTempo(const TempoRecEvent& e) { push_back(e); } 178 }; 179 180 //--------------------------------------------------------- 181 // TempoFifo 182 //--------------------------------------------------------- 183 184 class TempoFifo { 185 TempoRecEvent fifo[TEMPO_FIFO_SIZE]; 186 volatile int size; 187 int wIndex; 188 int rIndex; 189 190 public: TempoFifo()191 TempoFifo() { clear(); } 192 bool put(const TempoRecEvent& event); // returns true on fifo overflow 193 TempoRecEvent get(); 194 const TempoRecEvent& peek(int = 0); 195 void remove(); isEmpty()196 bool isEmpty() const { return size == 0; } clear()197 void clear() { size = 0, wIndex = 0, rIndex = 0; } getSize()198 int getSize() const { return size; } 199 }; 200 201 } // namespace MusECore 202 203 namespace MusEGlobal { 204 extern MusECore::TempoList tempomap; 205 extern MusECore::TempoRecList tempo_rec_list; 206 } 207 208 #endif 209