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