Ardour  9.0-pre0-582-g084a23a80d
temporal/temporal/tempo.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #pragma once
20 
21 #include <list>
22 #include <string>
23 #include <vector>
24 #include <cmath>
25 #include <exception>
26 #include <unordered_map>
27 
28 #include <boost/intrusive/list.hpp>
29 
30 #include <glibmm/threads.h>
31 
32 #include "pbd/command.h"
33 #include "pbd/enum_convert.h"
34 #include "pbd/integer_division.h"
35 #include "pbd/memento_command.h"
36 #include "pbd/rcu.h"
37 #include "pbd/signals.h"
39 
40 #include "temporal/visibility.h"
41 #include "temporal/beats.h"
42 #include "temporal/bbt_argument.h"
43 #include "temporal/bbt_time.h"
44 #include "temporal/domain_swap.h"
45 #include "temporal/superclock.h"
46 #include "temporal/timeline.h"
47 #include "temporal/types.h"
48 
49 /* A tempo map is built from 3 types of entities
50 
51  1) tempo markers
52  2) meter (time signature) markers
53  3) position markers
54 
55  Beats increase monotonically throughout the tempo map (BBT may not).
56 
57  The map has a single time domain at any time.
58 */
59 
60 namespace Temporal {
61 
62 class Meter;
63 class TempoMap;
64 class TempoMapCutBuffer;
65 
66 class MapOwned {
67  protected:
68  MapOwned (TempoMap const & map) : _map (&map) {}
69  virtual ~MapOwned () {}
70 
71  public:
72  TempoMap const & map() const { return *_map; }
73 
74  protected:
75  friend class TempoMap;
76  void set_map (TempoMap const & map) { _map = &map; }
77  TempoMap const * _map;
78 };
79 
80 /* Conceptually, Point is similar to timepos_t. However, whereas timepos_t can
81  * use the TempoMap to translate between time domains, Point cannot. Why not?
82  * Because Point is foundational in building the tempo map, and we cannot
83  * create a circular functional dependency between them. So a Point always has
84  * its superclock and beat time defined and no translation between them is possible.
85  */
86 
87 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct point_tag>> point_hook;
88 class /*LIBTEMPORAL_API*/ Point : public point_hook, public MapOwned {
89  public:
90  LIBTEMPORAL_API Point (TempoMap const & map, superclock_t sc, Beats const & b, BBT_Time const & bbt) : MapOwned (map), _sclock (sc), _quarters (b), _bbt (bbt) {}
92 
93  LIBTEMPORAL_API virtual ~Point() {}
94 
95  LIBTEMPORAL_API void set (superclock_t sc, Beats const & b, BBT_Time const & bbt) {
96  _sclock = sc;
97  _quarters = b;
98  _bbt = bbt;
99  }
100 
102  LIBTEMPORAL_API Beats const & beats() const { return _quarters; }
103  LIBTEMPORAL_API BBT_Time const & bbt() const { return _bbt; }
104  LIBTEMPORAL_API samplepos_t sample (int sr) const { return superclock_to_samples (sclock(), sr); }
105 
106  LIBTEMPORAL_API virtual timepos_t time() const = 0;
107 
109  bool operator() (Point const & a, Point const & b) const {
110  return a.sclock() < b.sclock();
111  }
112  bool operator() (Point const & a, superclock_t sc) const {
113  return a.sclock() < sc;
114  }
115  };
116 
118  bool operator() (Point const * a, Point const * b) const {
119  return a->sclock() < b->sclock();
120  }
121  };
122 
124  bool operator() (Point const & a, Point const & b) const {
125  return a.beats() < b.beats();
126  }
127  bool operator() (Point const & a, Beats const & beats) const {
128  return a.beats() < beats;
129  }
130  };
131 
133  bool operator() (Point const & a, Point const & b) const {
134  return a.bbt() < b.bbt();
135  }
136  bool operator() (Point const & a, BBT_Time const & bbt) const {
137  return a.bbt() < bbt;
138  }
139  };
140 
141  /* all time members are supposed to be synced at all times, so we need
142  test only one.
143  */
144  LIBTEMPORAL_API inline bool operator== (Point const & other) const { return _sclock == other._sclock; }
145  LIBTEMPORAL_API inline bool operator!= (Point const & other) const { return _sclock != other._sclock; }
146 
147  protected:
151 
152  void add_state (XMLNode &) const;
153 
154  protected:
155  friend class TempoMap;
157 };
158 
163  public:
164  enum Type {
166  Constant
167  };
168 
169  static std::string xml_node_name;
170 
171  Tempo (XMLNode const &);
172  virtual ~Tempo () {}
173 
178  Tempo (double npm, int8_t note_type)
179  : _npm (npm)
180  , _enpm (npm)
181  , _superclocks_per_note_type (double_npm_to_scpn (npm))
182  , _end_superclocks_per_note_type (double_npm_to_scpn (npm))
183  , _note_type (note_type)
184  , _locked_to_meter (false)
185  , _continuing (false)
186  {}
187 
188  Tempo (double npm, double enpm, int8_t note_type)
189  : _npm (npm)
190  , _enpm (npm)
191  , _superclocks_per_note_type (double_npm_to_scpn (npm))
192  , _end_superclocks_per_note_type (double_npm_to_scpn (enpm))
193  , _note_type (note_type)
194  , _locked_to_meter (false)
195  , _continuing (false)
196  {}
197 
198  /* these five methods should only be used to show and collect information to the user (for whom
199  * bpm as a floating point number is the obvious representation)
200  */
201  double note_types_per_minute () const { return ((double) superclock_ticks_per_second() * 60.0) / (double) _superclocks_per_note_type; }
202  double end_note_types_per_minute () const { return ((double) superclock_ticks_per_second() * 60.0) / (double) _end_superclocks_per_note_type; }
203  double quarter_notes_per_minute() const { return ((double) superclock_ticks_per_second() * 60.0 * 4.0) / (_note_type * (double) _superclocks_per_note_type); }
204  double samples_per_note_type(int sr) const { return superclock_to_samples (superclocks_per_note_type (), sr); }
205  double samples_per_quarter_note(int sr) const { return superclock_to_samples (superclocks_per_quarter_note(), sr); }
206 
207  void set_note_types_per_minute (double npm);
208 
209  int note_type () const { return _note_type; }
210 
212  return _superclocks_per_note_type;
213  }
214  superclock_t superclocks_per_note_type (int note_type) const {
215  return (_superclocks_per_note_type * _note_type) / note_type;
216  }
218  return superclocks_per_note_type (4);
219  }
221  return _end_superclocks_per_note_type;
222  }
224  return (_end_superclocks_per_note_type * _note_type) / note_type;
225  }
227  return end_superclocks_per_note_type (4);
228  }
229 
230  bool locked_to_meter () const { return _locked_to_meter; }
231  void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
232 
233  bool continuing() const { return _continuing; }
234  void set_continuing (bool yn);
235 
236  Type type() const { return _superclocks_per_note_type == _end_superclocks_per_note_type ? Constant : Ramped; }
237  bool ramped () const { return _superclocks_per_note_type != _end_superclocks_per_note_type; }
238 
239  XMLNode& get_state () const;
240  int set_state (XMLNode const&, int version);
241 
242  bool operator== (Tempo const & other) const {
243  return _superclocks_per_note_type == other._superclocks_per_note_type &&
244  _end_superclocks_per_note_type == other._end_superclocks_per_note_type &&
245  _note_type == other._note_type &&
246  _locked_to_meter == other._locked_to_meter &&
247  _continuing == other._continuing;
248  }
249 
250  bool operator!= (Tempo const & other) const {
251  return _superclocks_per_note_type != other._superclocks_per_note_type ||
252  _end_superclocks_per_note_type != other._end_superclocks_per_note_type ||
253  _note_type != other._note_type ||
254  _locked_to_meter != other._locked_to_meter ||
255  _continuing != other._continuing;
256  }
257 
258  protected:
259  double _npm;
260  double _enpm;
263  int8_t _note_type;
264  bool _locked_to_meter; /* XXX name has unclear meaning with nutempo */
265  bool _continuing; /* true if our effective end tempo is defined
266  * by the following tempo in the TempoMap;
267  * false if we use our own end tempo. */
268 
269  static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second()); }
270 
271  protected:
272  friend class TempoMap;
273  void set_end_npm (double);
274 };
275 
278  public:
279 
280  static std::string xml_node_name;
281 
282  Meter (XMLNode const &);
283  Meter (int8_t dpb, int8_t nv) : _note_value (nv), _divisions_per_bar (dpb) {}
284  Meter (Meter const & other) : _note_value (other._note_value), _divisions_per_bar (other._divisions_per_bar) {}
285 
286  virtual ~Meter () {}
287 
288  int divisions_per_bar () const { return _divisions_per_bar; }
289  int note_value() const { return _note_value; }
290 
291  int32_t ticks_per_grid () const { return (4 * Beats::PPQN) / _note_value; }
292 
293  inline bool operator==(const Meter& other) const { return _divisions_per_bar == other.divisions_per_bar() && _note_value == other.note_value(); }
294  inline bool operator!=(const Meter& other) const { return _divisions_per_bar != other.divisions_per_bar() || _note_value != other.note_value(); }
295 
296  Meter& operator=(Meter const & other) {
297  if (&other != this) {
298  _divisions_per_bar = other._divisions_per_bar;
299  _note_value = other._note_value;
300  }
301  return *this;
302  }
303 
304  BBT_Time bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const;
305  BBT_Time bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const;
306  BBT_Time round_to_bar (BBT_Time const &) const;
308  BBT_Time round_up_to_beat_div (BBT_Time const &, int beat_div) const;
309  BBT_Time round_up_to_beat (BBT_Time const & bbt) const { return round_up_to_beat_div (bbt, 1); }
310  BBT_Time round_to_beat (BBT_Time const &) const;
311  Beats to_quarters (BBT_Offset const &) const;
312 
313  XMLNode& get_state () const;
314  int set_state (XMLNode const&, int version);
315 
316  protected:
320  int8_t _note_value;
321  /* how many of '_note_value' make up a bar or measure */
323 };
324 
325 /* A MeterPoint is literally just the combination of a Meter with a Point
326  */
327 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct meterpoint_tag>> meter_hook;
328 class /*LIBTEMPORAL_API*/ MeterPoint : public Meter, public meter_hook, public virtual Point
329 {
330  public:
331  LIBTEMPORAL_API MeterPoint (TempoMap const & map, Meter const & m, superclock_t sc, Beats const & b, BBT_Time const & bbt) : Point (map, sc, b, bbt), Meter (m) {}
333  LIBTEMPORAL_API MeterPoint (Meter const & m, Point const & p) : Point (p), Meter (m) {}
334 
335  virtual ~MeterPoint () {}
336 
339 
340  LIBTEMPORAL_API bool operator== (MeterPoint const & other) const {
341  return Meter::operator== (other) && Point::operator== (other);
342  }
343  LIBTEMPORAL_API bool operator!= (MeterPoint const & other) const {
344  return Meter::operator!= (other) || Point::operator!= (other);
345  }
346 
348 
349  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
350 };
351 
352 /* A TempoPoint is a combination of a Tempo with a Point. However, if the temp
353  * is ramped, then at some point we will need to compute the ramp coefficient
354  * (_omega) and store it so that we can compute tempo-at-time and
355  * time-at-quarter-note on demand.
356  */
357 
358 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct tempo_tag>> tempo_hook;
359 class /*LIBTEMPORAL_API*/ TempoPoint : public Tempo, public tempo_hook, public virtual Point
360 {
361  public:
362  LIBTEMPORAL_API TempoPoint (TempoMap const & map, Tempo const & t, superclock_t sc, Beats const & b, BBT_Time const & bbt) : Point (map, sc, b, bbt), Tempo (t), _omega (0.) {}
363  LIBTEMPORAL_API TempoPoint (Tempo const & t, Point const & p) : Point (p), Tempo (t), _omega (0.) {}
365 
366  virtual ~TempoPoint () {}
367 
368  /* just change the tempo component, without moving */
370  *((Tempo*)this) = t;
371  return *this;
372  }
373 
374  /* Given that this tempo point controls tempo for the time indicated by
375  * the argument of the following 3 functions, return information about
376  * that time. The first 3 return convert between domains (with
377  * ::sample_at() just being a convenience function); the third returns
378  * information about the tempo at that time.
379  */
380 
384 
385  /* XXX at some point, we have had discussions about representing tempo
386  * as a rational number rather than a double. We have not reached that
387  * point yet (Nov 2021), and so at this point, this method is the
388  * canonical way to get "bpm at position" from a TempoPoint object.
389  */
390 
393  }
394 
395  LIBTEMPORAL_API double omega() const { return _omega; }
396 
398  LIBTEMPORAL_API void compute_omega_from_distance_and_next_tempo (Beats const & quarter_duration, TempoPoint const & next_tempo);
399  LIBTEMPORAL_API void compute_omega_from_quarter_duration (Beats const & quarter_duration, superclock_t end_scpqn);
400 
401  LIBTEMPORAL_API bool actually_ramped () const { return Tempo::ramped() && ( _omega != 0); /* do not need to check both omegas */ }
402 
404  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
405 
406  LIBTEMPORAL_API bool operator== (TempoPoint const & other) const {
407  return Tempo::operator== (other) && Point::operator== (other);
408  }
409  LIBTEMPORAL_API bool operator!= (TempoPoint const & other) const {
410  return Tempo::operator!= (other) || Point::operator!= (other);
411  }
412 
415 
416  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
417 
418  private:
419  double _omega;
420 
421  friend TempoMap;
422  void set_omega (double v);
423 };
424 
441 {
442  public:
443  TempoMetric (TempoPoint const & t, MeterPoint const & m);
444  virtual ~TempoMetric () {}
445 
446  superclock_t reftime() const { return _reftime; }
447 
448  TempoPoint const & tempo() const { return *_tempo; }
449  MeterPoint const & meter() const { return *_meter; }
450 
451  TempoPoint & get_editable_tempo() const { return *const_cast<TempoPoint*> (_tempo); }
452  MeterPoint & get_editable_meter() const { return *const_cast<MeterPoint*> (_meter); }
453 
454  /* even more convenient wrappers for individual aspects of a
455  * TempoMetric (i.e. just tempo or just meter information required
456  */
457 
458  superclock_t superclock_at (Beats const & qn) const { return _tempo->superclock_at (qn); }
459  samplepos_t sample_at (Beats const & qn) const { return _tempo->sample_at (qn); }
460  Beats quarters_at (BBT_Time const & bbt) const { return _meter->quarters_at (bbt); }
461  BBT_Argument bbt_at (Beats const & beats) const { return BBT_Argument (reftime(), _meter->bbt_at (beats)); }
462 
463  superclock_t superclocks_per_note_type () const { return _tempo->superclocks_per_note_type (); }
464  superclock_t end_superclocks_per_note_type () const {return _tempo->end_superclocks_per_note_type (); }
465  superclock_t superclocks_per_note_type (int note_type) const {return _tempo->superclocks_per_note_type (note_type); }
466  superclock_t superclocks_per_quarter_note () const {return _tempo->superclocks_per_quarter_note (); }
467 
468  int note_type () const { return _tempo->note_type(); }
469  int divisions_per_bar () const { return _meter->divisions_per_bar(); }
470  int note_value() const { return _meter->note_value(); }
471  BBT_Argument bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const { return BBT_Argument (reftime(), _meter->bbt_add (bbt, add)); }
472  BBT_Argument bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const { return BBT_Argument (reftime(), _meter->bbt_subtract (bbt, sub)); }
473  BBT_Argument round_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_to_bar (bbt)); }
474  BBT_Argument round_up_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_up_to_bar (bbt)); }
475  Beats to_quarters (BBT_Offset const & bbo) const { return _meter->to_quarters (bbo); }
476 
477  /* combination methods that require both tempo and meter information */
478 
480  return superclocks_per_grid () * _meter->divisions_per_bar();
481  }
483  return PBD::muldiv_round (_tempo->superclocks_per_note_type(), _tempo->note_type(), (int64_t) _meter->note_value());
484  }
485 
487  if (!_tempo->actually_ramped()) {
488  return _tempo->superclocks_per_note_type ();
489  }
490  return _tempo->superclocks_per_note_type() * exp (-_tempo->omega() * (sc - _tempo->sclock()));
491  }
492 
493  BBT_Argument bbt_at (timepos_t const &) const;
495 
497  return superclock_to_samples (superclocks_per_bar (), sr);
498  }
499 
500  Beats quarters_at_sample (samplepos_t sc) const { return quarters_at_superclock (samples_to_superclock (sc, TEMPORAL_SAMPLE_RATE)); }
501  Beats quarters_at_superclock (superclock_t sc) const { return _tempo->quarters_at_superclock (sc); }
502 
503  protected:
507 
508 };
509 
510 /* A music time point is a place where BBT time is reset from
511  * whatever it would be when just inferring from the usual counting. Its
512  * position is given by a Point that might use superclock or Beats, and the
513  * Point's BBT time member is overwritten.
514  */
515 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct bartime_tag>> bartime_hook;
516 class /*LIBTEMPORAL_API*/ MusicTimePoint : public bartime_hook, public virtual TempoPoint, public virtual MeterPoint
517 {
518  public:
519  LIBTEMPORAL_API MusicTimePoint (TempoMap const & map, superclock_t sc, Beats const & b, BBT_Time const & bbt, Tempo const & t, Meter const & m, std::string name = std::string())
520  : Point (map, sc, b, bbt), TempoPoint (t, *this), MeterPoint (m, *this), _name (name) {}
521 
523 
524  virtual ~MusicTimePoint () {}
525 
526  LIBTEMPORAL_API bool operator== (MusicTimePoint const & other) const {
527  return TempoPoint::operator== (other) && MeterPoint::operator== (other);
528  }
529 
531 
532  LIBTEMPORAL_API std::string name() const { return _name; }
533  LIBTEMPORAL_API void set_name (std::string const &);
534 
536 
537  private:
538  std::string _name;
539 };
540 
545 /* TempoMap concepts
546 
547  we have several different ways of talking about time:
548 
549  * PULSE : whole notes, just because. These are linearly related to any other
550  note type, so if you know a number of pulses (whole notes), you
551  know the corresponding number of any other note type (e.g. quarter
552  notes).
553 
554  * QUARTER NOTES : just what the name says. A lot of MIDI software and
555  concepts assume that a "beat" is a quarter-note.
556 
557  * BEAT : a fraction of a PULSE. Defined by the meter in effect, so requires
558  meter (time signature) information to convert to/from PULSE or QUARTER NOTES.
559  In a 5/8 time, a BEAT is 1/8th note. In a 4/4 time, a beat is quarter note.
560  This means that measuring time in BEATS is potentially non-linear (if
561  the time signature changes, there will be a different number of BEATS
562  corresponding to a given time in any other unit).
563 
564  * SUPERCLOCK : a very high resolution clock whose frequency
565  has as factors all common sample rates and all common note
566  type divisors. Related to MINUTES or SAMPLES only when a
567  sample rate is known. Related to PULSE or QUARTER NOTES only
568  when a tempo is known.
569 
570  * MINUTES : wallclock time measurement. related to SAMPLES or SUPERCLOCK
571  only when a sample rate is known.
572 
573 
574  * SAMPLES : audio time measurement. Related to MINUTES or SUPERCLOCK only
575  when a sample rate is known
576 
577  * BBT : bars|beats|ticks ... linearly related to BEATS but with the added
578  semantics of bars ("measures") added, in which beats are broken up
579  into groups of bars ("measures"). Requires meter (time signature)
580  information to compute to/from a given BEATS value. Contains no
581  additional time information compared to BEATS, but does have
582  additional semantic information.
583 
584  Nick sez: not every note onset is on a tick
585  Paul wonders: if it's 8 samples off, does it matter?
586  Nick sez: it should not phase with existing audio
587 
588  */
589 
591 {
592  public:
593  TempoMapPoint (TempoMap const & map, TempoMetric const & tm, superclock_t sc, Beats const & q, BBT_Time const & bbt)
594  : Point (map, sc, q, bbt), TempoMetric (tm) {}
596 
597  bool is_explicit_meter() const { return _meter->sclock() == sclock(); }
598  bool is_explicit_tempo() const { return _tempo->sclock() == sclock(); }
599  bool is_explicit_position() const { return false; }
600  bool is_explicit () const { return is_explicit_meter() || is_explicit_tempo() || is_explicit_position(); }
601 
602  timepos_t time() const { if (is_explicit_meter()) { return _meter->time(); } else if (is_explicit_tempo()) { return _tempo->time(); } else { return timepos_t::from_superclock (sclock()); } }
603 };
604 
605 typedef std::vector<TempoMapPoint> TempoMapPoints;
606 
607 typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
608 typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
609 typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
610 typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
611 
612 /* An object used to retain "position" across calls to get_grid()
613  */
615 {
616  public:
617  GridIterator () : sclock (0), tempo (nullptr), meter (nullptr), end (0), bar_mod (0), beat_div (1), valid (false), map (nullptr) {}
618  GridIterator (TempoMap const & m, TempoPoint const * tp, MeterPoint const * mp, superclock_t sc, Beats const & b, BBT_Time const & bb, Points::const_iterator p, superclock_t e,
619  uint32_t bmod, uint32_t bdiv)
620  : sclock (sc)
621  , beats (b)
622  , bbt (bb)
623  , tempo (tp)
624  , meter (mp)
625  , points_iterator (p)
626  , end (e)
627  , bar_mod (bmod)
628  , beat_div (bdiv)
629  , valid (false)
630  , map (&m)
631  {
632  valid = (tempo && meter);
633  }
634 
635  void set (TempoMap const & m, TempoPoint const * tp, MeterPoint const * mp, superclock_t sc, Beats const & b, BBT_Time const & bb, Points::const_iterator p, superclock_t e,
636  uint32_t bmod, uint32_t bdiv) {
637  map = &m;
638  tempo = tp;
639  meter = mp;
640  sclock = sc;
641  beats = b;
642  bbt = bb;
643  points_iterator = p;
644  end = e;
645  bar_mod = bmod;
646  beat_div = bdiv;
647  }
648 
649  bool valid_for (TempoMap const & map, superclock_t start, uint32_t bar_mod, uint32_t beat_div) const;
650  void catch_up_to (superclock_t e) { end = e; }
651  void invalidate () { valid = false; }
652 
653 
654  /* These 3 members hold the position of the last discovered grid point */
658 
659  /* These 3 members hold the TempoMetric information that was in effect
660  * at the *end* of the last use of the GridIterator
661  */
662  TempoPoint const * tempo;
663  MeterPoint const * meter;
664 
665  /* the iterator in the tempo map's _points list that points to the next
666  * point to be considered, or _points.end()
667  */
668  Points::const_iterator points_iterator;
669 
670  /* The position of the end of the last use of the GridIterator. For the
671  iterator to be considered valid on the next call, the start must
672  match this value (see ::valid_for() above).
673  */
675 
676 
677  /* bar modulus and beat division used by GridIterator. These must match
678  the current call to ::get_grid() for the iterator to
679  be valid.
680  */
681 
682  uint32_t bar_mod;
683  uint32_t beat_div;
684 
685  private:
686  bool valid;
687 
688  TempoMap const * map; /* nullptr or the map instance this GridIterator
689  * was last used with.
690  */
691 };
692 
693 class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
694 {
695  /* Any given thread must be able to carry out tempo-related arithmetic
696  * and time domain conversions using a consistent version of a
697  * TempoMap. The map could be updated at any time, and for any reason
698  * (typically from a GUI thread), but some other thread could be
699  * using the map to convert from audio to music time (for example).
700  *
701  * We do not want to use locks for this - this math may happen in a
702  * realtime thread, and even worse, the lock may need to be held for
703  * long periods of time in order to have the desired effect: a thread
704  * may be performing some tempo-based arithmetic as part of a complex
705  * operation that requires multiple steps. The tempo map it uses must
706  * remain consistent across all steps, and so we would have to hold the
707  * lock across them all. That would create awkward and difficult
708  * semantics for map users - somewhat arbitrary rules about how long
709  * one could hold the map for, etc.
710  *
711  * Elsewhere in the codebase, we use RCU to solve this sort of
712  * issue. For example, if we need to operate on the current list of
713  * Routes, we get read-only copy of the list, and iterate over it,
714  * knowing that even if the canonical version is being changed, the
715  * copy we are using will not.
716  *
717  * However, the tempo map's use is often implicit rather than
718  * explicit. The callstack to convert between an audio domain time and
719  * a music domain time should not require passing a tempo map into
720  * every call.
721  *
722  * The approach taken here is to use a combination of RCU and
723  * thread-local variables. Any given thread is by definition ... single
724  * threaded. If the thread has a thread-local copy of a tempo map, it
725  * will not change except at explicit calls to change it. The tempo map
726  * can be accessed from any method executed by the thread. But the
727  * relationship between the thread-local copy and "actual" tempo map(s)
728  * is managed via RCU, meaning that read-only access is cheap (no
729  * actual copy required).
730  *
731  */
732  public:
733  typedef std::shared_ptr<TempoMap const> SharedPtr;
734  typedef std::shared_ptr<TempoMap> WritableSharedPtr;
735  private:
736  static thread_local SharedPtr _tempo_map_p;
738  public:
739  LIBTEMPORAL_API static void init ();
740 
742  LIBTEMPORAL_API static SharedPtr use() { assert (_tempo_map_p); return _tempo_map_p; }
744 
745  /* Used only by the ARDOUR::AudioEngine API to reset the process thread
746  * tempo map only when it has changed.
747  */
748 
749  LIBTEMPORAL_API static SharedPtr read() { return _map_mgr.reader(); }
750 
751  /* Because WritableSharedPtr can be implicitly cast to SharedPtr, this
752  * can be used on either a write_copy()'ed map, or one obtained via the
753  * RCU reader() method.
754  */
755  LIBTEMPORAL_API static void set (SharedPtr new_map) { _tempo_map_p = new_map; }
756 
757  /* API for typical tempo map changes */
758 
762 
763  /* not part of public API */
764  superclock_t reftime(TempoPoint const &, MeterPoint const &) const;
765 
766  /* and now on with the rest of the show ... */
767 
768  public:
770  LIBTEMPORAL_API TempoMap (Tempo const& initial_tempo, Meter const& initial_meter);
772  LIBTEMPORAL_API TempoMap (XMLNode const&, int version);
774 
776 
778 
779  /* methods which modify the map. These must all be called using
780  * RCU-style semantics: get a writable copy, modify it, then update via
781  * the RCU manager.
782  */
783 
786 
787  LIBTEMPORAL_API bool remove_time (timepos_t const & pos, timecnt_t const & duration);
788 
790 
791  LIBTEMPORAL_API void set_bartime (BBT_Time const &, timepos_t const &, std::string name = std::string());
792  LIBTEMPORAL_API void remove_bartime (MusicTimePoint const & tp, bool with_reset = true);
793  LIBTEMPORAL_API void replace_bartime (MusicTimePoint & tp, bool with_reset = true);
794 
797 
798  LIBTEMPORAL_API void replace_tempo (TempoPoint const & old, Tempo const & thenew, timepos_t const &);
799 
802 
803  LIBTEMPORAL_API void remove_tempo (TempoPoint const &, bool with_reset = true);
804  LIBTEMPORAL_API void remove_meter (MeterPoint const &, bool with_reset = true);
805 
806  /* these are a convenience method that just wrap some odd semantics */
807  LIBTEMPORAL_API bool move_tempo (TempoPoint const & point, timepos_t const & destination, bool push = false);
808  LIBTEMPORAL_API bool move_meter (MeterPoint const & point, timepos_t const & destination, bool push = false);
809 
810  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
811 
812  LIBTEMPORAL_API void constant_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
813  LIBTEMPORAL_API void ramped_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
814 
815  LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm);
817 
818  LIBTEMPORAL_API bool clear_tempos_before (timepos_t const &, bool stop_at_music_time);
819  LIBTEMPORAL_API bool clear_tempos_after (timepos_t const &, bool stop_at_music_time);
820 
821  /* END OF MODIFYING METHODS */
822 
823  /* rather than giving direct access to the intrusive list members,
824  * offer one that uses an STL container instead.
825  */
826 
827  typedef std::list<Point const *> Metrics;
828 
829  void get_metrics (Metrics& m) const {
830  for (auto const & p : _points) {
831  m.push_back (&p);
832  }
833  }
834 
835  LIBTEMPORAL_API bool can_remove (TempoPoint const &) const;
836  LIBTEMPORAL_API bool can_remove (MeterPoint const &) const;
837 
838  LIBTEMPORAL_API bool is_initial (TempoPoint const &) const;
839  LIBTEMPORAL_API bool is_initial (MeterPoint const &) const;
840 
841  LIBTEMPORAL_API uint32_t n_meters() const;
842  LIBTEMPORAL_API uint32_t n_tempos() const;
843 
846 
849 
850  LIBTEMPORAL_API bool tempo_exists_before (TempoPoint const & t) const { return (bool) previous_tempo (t); }
851  LIBTEMPORAL_API bool tempo_exists_after (TempoPoint const & t) const { return (bool) next_tempo (t); }
852 
853  LIBTEMPORAL_API Meter const* next_meter (Meter const &) const;
854 
856 
857  /* These return the TempoMetric in effect at the given time. If
858  can_match is true, then the TempoMetric may refer to a Tempo or
859  Meter at the given time. If can_match is false, the TempoMetric will
860  only refer to the Tempo or Metric preceding the given time.
861  */
862  LIBTEMPORAL_API TempoMetric metric_at (Beats const &, bool can_match = true) const;
863  LIBTEMPORAL_API TempoMetric metric_at (BBT_Argument const &, bool can_match = true) const;
864 
865  LIBTEMPORAL_API TempoMapCutBuffer* cut (timepos_t const & start, timepos_t const & end, bool ripple);
867  LIBTEMPORAL_API void paste (TempoMapCutBuffer const &, timepos_t const & position, bool ripple, std::string = std::string());
868 
869  LIBTEMPORAL_API void shift (timepos_t const & at, BBT_Offset const & by);
870  LIBTEMPORAL_API void shift (timepos_t const & at, timecnt_t const & by);
871 
872  private:
873  template<typename TimeType, typename Comparator> TempoPoint const & _tempo_at (TimeType when, Comparator cmp) const {
874  assert (!_tempos.empty());
875 
876  if (_tempos.size() == 1) {
877  return _tempos.front();
878  }
879 
880  Tempos::const_iterator prev = _tempos.end();
881  for (Tempos::const_iterator t = _tempos.begin(); t != _tempos.end(); ++t) {
882  if (cmp (*t, when)) {
883  prev = t;
884  } else {
885  break;
886  }
887  }
888  if (prev == _tempos.end()) {
889  return _tempos.front();
890  }
891  return *prev;
892  }
893 
894  template<typename TimeType, typename Comparator> MeterPoint const & _meter_at (TimeType when, Comparator cmp) const {
895  assert (!_meters.empty());
896 
897  if (_meters.size() == 1) {
898  return _meters.front();
899  }
900 
901  Meters::const_iterator prev = _meters.end();
902  for (Meters::const_iterator m = _meters.begin(); m != _meters.end(); ++m) {
903  if (cmp (*m, when)) {
904  prev = m;
905  } else {
906  break;
907  }
908  }
909  if (prev == _meters.end()) {
910  return _meters.front();
911  }
912  return *prev;
913  }
914 
915  public:
916  LIBTEMPORAL_API MeterPoint const& meter_at (timepos_t const & p) const;
918  LIBTEMPORAL_API MeterPoint const& meter_at (Beats const & b) const { return _meter_at (b, Point::beat_comparator()); }
919  LIBTEMPORAL_API MeterPoint const& meter_at (BBT_Argument const & bbt) const { return _meter_at (bbt, Point::bbt_comparator()); }
920 
921  LIBTEMPORAL_API TempoPoint const& tempo_at (timepos_t const & p) const;
923  LIBTEMPORAL_API TempoPoint const& tempo_at (Beats const & b) const { return _tempo_at (b, Point::beat_comparator()); }
924  LIBTEMPORAL_API TempoPoint const& tempo_at (BBT_Argument const & bbt) const { return _tempo_at (bbt, Point::bbt_comparator()); }
925 
928 
929  /* convenience function that hides some complexities behind fetching
930  * the bpm at position
931  */
933 
934  /* convenience functions */
936  return metric_at (bbt).round_to_bar (bbt);
937  }
939  return metric_at (bbt).round_up_to_bar (bbt);
940  }
941 
944 
947 
951 
955 
956  /* ways to walk along the tempo map, measure distance between points,
957  * etc.
958  */
959 
962 
964  LIBTEMPORAL_API Beats bbtwalk_to_quarters (Beats const & start, BBT_Offset const & distance) const;
966 
968 
970 
971  Tempos const & tempos() const { return _tempos; }
972  Meters const & meters() const { return _meters; }
973  MusicTimes const & bartimes() const { return _bartimes; }
974 
975 
976  LIBTEMPORAL_API Points::const_iterator get_grid (TempoMapPoints & points, superclock_t start, superclock_t end, uint32_t bar_mod = 0, uint32_t beat_div = 1) const;
977  LIBTEMPORAL_API void get_grid (GridIterator& iter, TempoMapPoints& ret, superclock_t rstart, superclock_t end, uint32_t bar_mod = 0, uint32_t beat_div = 1) const;
978 
979  /* This version exists for Lua bindings, to avoid having to wrap Points::iterator etc. */
980  LIBTEMPORAL_API void grid (TempoMapPoints& points, superclock_t start, superclock_t end, uint32_t bar_mod = 0, uint32_t beat_div = 1) const {
981  get_grid (points, start, end, bar_mod, beat_div);
982  }
983 
984  struct EmptyTempoMapException : public std::exception {
985  virtual const char* what() const throw() { return "TempoMap is empty"; }
986  };
987 
988  LIBTEMPORAL_API void dump (std::ostream&) const;
989 
991 
993 
996 
997  LIBTEMPORAL_API void midi_clock_beat_at_or_after (samplepos_t const pos, samplepos_t& clk_pos, uint32_t& clk_beat) const;
998 
999  static void map_assert (bool expr, char const * exprstr, char const * file, int line);
1000 
1001  private:
1006 
1010 
1015 
1017 
1021 
1022  void add_point (Point &);
1023 
1025  void reset_starting_at (Beats const &);
1026 
1027  void remove_point (Point const &);
1028 
1029  void copy_points (TempoMap const & other);
1030 
1032 
1033  template<typename T, typename T1> struct const_traits {
1034  typedef Points::const_iterator iterator_type;
1035  typedef TempoPoint const * tempo_point_type;
1036  typedef MeterPoint const * meter_point_type;
1037  using time_reference = T;
1038  using time_type = T1;
1039  };
1040 
1041  template<typename T, typename T1> struct non_const_traits {
1042  typedef Points::iterator iterator_type;
1045  using time_reference = T;
1046  using time_type = T1;
1047  };
1048 
1049  /* A somewhat complex method that sets a TempoPoint* and MeterPoint* to
1050  * refer to the correct tempo and meter points for the given start
1051  * time.
1052  *
1053  * It also returns an iterator which may point at the latter of the two
1054  * points (tempo & meter; always the meter point if they are at the
1055  * same time) OR may point at the iterator *after* the latter of the
1056  * two, depending on whether or not @p ret_iterator_after_not_at is
1057  * true or false.
1058  *
1059  * If @p can_match is true, the points used can be located at the
1060  * given time. If false, they must be before it. Setting it to false is
1061  * useful when you need to know the TempoMetric in effect at a given
1062  * time if there was no tempo or meter point at that time.
1063  *
1064  * The templated structure here is to avoid code duplication in 2
1065  * separate versions of this method, one that would be const, and one
1066  * that would be non-const. This is a challenging problem in C++, and
1067  * seems best solved by using a "traits" object as shown here.
1068  *
1069  * The begini, endi, tstart and mstart arguments are an additional
1070  * complication. If we try to use e.g. _points.begin() inside the
1071  * method, which is labelled const, we will always get the const
1072  * version of the iterator. This const iterator type will conflict with
1073  * the non-const iterator type defined by the "non_const_traits"
1074  * type. The same happens with _tempos.front() etc. This problem is
1075  * addressed by calling these methods in the caller method, which maybe
1076  * const or non-const, and will provide appropriate versions based on that.
1077  */
1078 
1079  template<class constness_traits_t> typename constness_traits_t::iterator_type
1080  _get_tempo_and_meter (typename constness_traits_t::tempo_point_type &,
1081  typename constness_traits_t::meter_point_type &,
1082  typename constness_traits_t::time_reference (Point::*)() const,
1083  typename constness_traits_t::time_type,
1084  typename constness_traits_t::iterator_type begini,
1085  typename constness_traits_t::iterator_type endi,
1086  typename constness_traits_t::tempo_point_type tstart,
1087  typename constness_traits_t::meter_point_type mstart,
1088  bool can_match,
1089  bool ret_iterator_after_not_at) const;
1090 
1091  /* fetch non-const tempo/meter pairs and iterator (used in
1092  * ::reset_starting_at() in which we will modify points.
1093  */
1094 
1095  Points::iterator get_tempo_and_meter (TempoPoint *& t, MeterPoint *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) {
1096 
1097  /* because `this` is non-const (because the method is not
1098  * marked const), the following:
1099 
1100  _points.begin()
1101  _points.end()
1102  _tempos.front()
1103  _meters.front()
1104 
1105  will all be the non-const versions of these methods.
1106  */
1107 
1108  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1109  return _get_tempo_and_meter<non_const_traits<superclock_t, superclock_t> > (t, m, &Point::sclock, sc, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
1110  }
1111 
1112  /* fetch const tempo/meter pairs and iterator (used in metric_at() and
1113  * other similar call sites where we do not modify the map
1114  */
1115 
1116  Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) const {
1117  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1118  return _get_tempo_and_meter<const_traits<superclock_t, superclock_t> > (t, m, &Point::sclock, sc, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
1119  }
1120  Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, Beats const & b, bool can_match, bool ret_iterator_after_not_at) const {
1121  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1122  return _get_tempo_and_meter<const_traits<Beats const &, Beats> > (t, m, &Point::beats, b, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
1123  }
1124  Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, BBT_Argument const & bbt, bool can_match, bool ret_iterator_after_not_at) const {
1125 
1126  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1127 
1128  /* Skip through the tempo map to find the tempo and meter in
1129  * effect at the bbt's "reference" time, and use them as the
1130  * starting point for the normal operation of
1131  * _get_tempo_and_meter ()
1132  */
1133 
1134  Tempos::const_iterator tp = _tempos.begin();
1135  Meters::const_iterator mp = _meters.begin();
1136  superclock_t ref = bbt.reference();
1137 
1138  if (ref != 0) {
1139  while (tp != _tempos.end()) {
1140  Tempos::const_iterator nxt = tp; ++nxt;
1141  if (nxt == _tempos.end() || nxt->sclock() > ref) {
1142  break;
1143  }
1144  tp = nxt;
1145  }
1146  while (mp != _meters.end()) {
1147  Meters::const_iterator nxt = mp; ++nxt;
1148  if (nxt == _meters.end() || mp->sclock() > ref) {
1149  break;
1150  }
1151  mp = nxt;
1152  }
1153  }
1154 
1155  return _get_tempo_and_meter<const_traits<BBT_Time const &, BBT_Time> > (t, m, &Point::bbt, bbt, _points.begin(), _points.end(), &(*tp), &(*mp), can_match, ret_iterator_after_not_at);
1156  }
1157 
1158  /* This is private, and should not be callable from outside the map
1159  because of potential confusion between samplepos_t and
1160  superclock_t. The timepos_t variant of ::metric_at() handles any
1161  samplepos_t-passing call.
1162  */
1163  TempoMetric metric_at (superclock_t, bool can_match = true) const;
1164 
1165  /* parsing legacy tempo maps */
1166 
1168  {
1170  double pulses;
1173  double note_type;
1174  bool continuing; /* "clamped" in actual legacy stuff */
1175  };
1176 
1178  {
1180  double pulses;
1182  double beat;
1184  double note_type;
1185  };
1186 
1189  int set_state_3x (XMLNode const &);
1190  TempoPoint & set_tempo (Tempo const & t, timepos_t const & time, Beats const & beats);
1191 
1192  friend class TempoPoint;
1193  friend class MeterPoint;
1194  friend class TempoMetric;
1195 
1196  bool solve_ramped_twist (TempoPoint&, TempoPoint&); /* this is implemented by iteration, and it might fail. */
1197  bool solve_constant_twist (TempoPoint&, TempoPoint&); //TODO: currently also done by iteration; should be possible to calculate directly
1198 
1202 
1203  void reset_section (Points::iterator& begin, Points::iterator& end, superclock_t, TempoMetric& metric);
1204 
1205  TempoMapCutBuffer* cut_copy (timepos_t const & start, timepos_t const & end, bool copy, bool ripple);
1206 
1207  void fill_grid_by_walking (TempoMapPoints& ret, Points::const_iterator& p, TempoMetric& metric, superclock_t& start, superclock_t rstart,
1208  superclock_t end, int bar_mod, int beat_div, Beats& beats, BBT_Time& bbt) const;
1209  void fill_grid_with_final_metric (TempoMapPoints& ret, TempoMetric metric, superclock_t start, superclock_t rstart, superclock_t end, int bar_mod, int beat_div, Beats beats, BBT_Time bbt) const;
1210 };
1211 
1213 {
1214  public:
1217 
1218  timecnt_t duration() const { return _duration; }
1219 
1220  void add_start_tempo (Tempo const & t);
1221  void add_end_tempo (Tempo const & t);
1222  void add_start_meter (Meter const & t);
1223  void add_end_meter (Meter const & t);
1224 
1225  Tempo const * start_tempo () const { return _start_tempo; }
1226  Tempo const * end_tempo () const { return _end_tempo; }
1227 
1228  Meter const * start_meter () const { return _start_meter; }
1229  Meter const * end_meter () const { return _end_meter; }
1230 
1231  typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
1232  typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
1233  typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
1234  typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
1235 
1236  void add (TempoPoint const &);
1237  void add (MeterPoint const &);
1238  void add (MusicTimePoint const &);
1239  void add (Point const &);
1240 
1241  void clear ();
1242  void dump (std::ostream&);
1243 
1244  Tempos const & tempos() const { return _tempos; }
1245  Meters const & meters() const { return _meters; }
1246  MusicTimes const & bartimes() const { return _bartimes; }
1247  Points const & points() const { return _points; }
1248 
1249  bool empty() const {
1250  return _tempos.empty() && _meters.empty() && _bartimes.empty() && _points.empty();
1251  }
1252 
1253  private:
1259 
1264 };
1265 
1267  public:
1268 
1269  TempoCommand (std::string const & name, XMLNode const * before, XMLNode const * after);
1272 
1273  const std::string& name () const { return _name; }
1274 
1275  void operator() ();
1276  void undo ();
1277 
1278  XMLNode & get_state () const;
1279 
1280  protected:
1281  std::string _name;
1282  XMLNode const * _before;
1283  XMLNode const * _after;
1284 };
1285 
1286 } /* end of namespace Temporal */
1287 
1288 #ifdef COMPILER_MSVC
1289 #pragma warning(disable:4101)
1290 #endif
1291 
1292 namespace std {
1293 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMapPoint const &);
1294 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Tempo const &);
1295 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Meter const &);
1296 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Point const &);
1297 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoPoint const &);
1298 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MeterPoint const &);
1299 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MusicTimePoint const &);
1300 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMetric const &);
1301 }
1302 
std::ostream & operator<<(std::ostream &o, ARDOUR::Bundle const &)
static const int32_t PPQN
Definition: beats.h:67
bool valid_for(TempoMap const &map, superclock_t start, uint32_t bar_mod, uint32_t beat_div) const
Points::const_iterator points_iterator
GridIterator(TempoMap const &m, TempoPoint const *tp, MeterPoint const *mp, superclock_t sc, Beats const &b, BBT_Time const &bb, Points::const_iterator p, superclock_t e, uint32_t bmod, uint32_t bdiv)
void catch_up_to(superclock_t e)
void set(TempoMap const &m, TempoPoint const *tp, MeterPoint const *mp, superclock_t sc, Beats const &b, BBT_Time const &bb, Points::const_iterator p, superclock_t e, uint32_t bmod, uint32_t bdiv)
TempoMap const & map() const
MapOwned(TempoMap const &map)
void set_map(TempoMap const &map)
MeterPoint(TempoMap const &map, XMLNode const &)
MeterPoint(TempoMap const &map, Meter const &m, superclock_t sc, Beats const &b, BBT_Time const &bbt)
Beats quarters_at(BBT_Time const &bbt) const
XMLNode & get_state() const
BBT_Time bbt_at(Beats const &beats) const
bool operator==(MeterPoint const &other) const
MeterPoint(Meter const &m, Point const &p)
bool operator!=(MeterPoint const &other) const
BBT_Time bbt_subtract(BBT_Time const &bbt, BBT_Offset const &sub) const
BBT_Time round_up_to_bar(BBT_Time const &) const
Meter & operator=(Meter const &other)
BBT_Time round_up_to_beat_div(BBT_Time const &, int beat_div) const
Meter(XMLNode const &)
BBT_Time round_up_to_beat(BBT_Time const &bbt) const
Meter(int8_t dpb, int8_t nv)
BBT_Time bbt_add(BBT_Time const &bbt, BBT_Offset const &add) const
BBT_Time round_to_bar(BBT_Time const &) const
Beats to_quarters(BBT_Offset const &) const
bool operator==(const Meter &other) const
Meter(Meter const &other)
int set_state(XMLNode const &, int version)
int32_t ticks_per_grid() const
XMLNode & get_state() const
bool operator!=(const Meter &other) const
BBT_Time round_to_beat(BBT_Time const &) const
static std::string xml_node_name
bool operator==(MusicTimePoint const &other) const
XMLNode & get_state() const
void set_name(std::string const &)
MusicTimePoint(TempoMap const &map, superclock_t sc, Beats const &b, BBT_Time const &bbt, Tempo const &t, Meter const &m, std::string name=std::string())
MusicTimePoint(TempoMap const &map, XMLNode const &)
void set(superclock_t sc, Beats const &b, BBT_Time const &bbt)
void add_state(XMLNode &) const
bool operator!=(Point const &other) const
samplepos_t sample(int sr) const
virtual timepos_t time() const =0
Point(TempoMap const &map, superclock_t sc, Beats const &b, BBT_Time const &bbt)
Point(TempoMap const &map, XMLNode const &)
superclock_t sclock() const
Beats const & beats() const
bool operator==(Point const &other) const
void map_reset_set_sclock_for_sr_change(superclock_t sc)
BBT_Time const & bbt() const
const std::string & name() const
TempoCommand(std::string const &name, XMLNode const *before, XMLNode const *after)
TempoCommand(XMLNode const &)
XMLNode & get_state() const
void dump(std::ostream &)
void add_end_tempo(Tempo const &t)
void add_end_meter(Meter const &t)
void add_start_meter(Meter const &t)
TempoMapCutBuffer(timecnt_t const &)
void add(MeterPoint const &)
void add(MusicTimePoint const &)
boost::intrusive::list< TempoPoint, boost::intrusive::base_hook< tempo_hook > > Tempos
boost::intrusive::list< MusicTimePoint, boost::intrusive::base_hook< bartime_hook > > MusicTimes
boost::intrusive::list< Point, boost::intrusive::base_hook< point_hook > > Points
void add(TempoPoint const &)
MusicTimes const & bartimes() const
boost::intrusive::list< MeterPoint, boost::intrusive::base_hook< meter_hook > > Meters
void add_start_tempo(Tempo const &t)
void add(Point const &)
TempoMapPoint(TempoMap const &map, TempoMetric const &tm, superclock_t sc, Beats const &q, BBT_Time const &bbt)
void copy_points(TempoMap const &other)
static void abort_update()
bool set_continuing(TempoPoint &, bool)
MeterPoint const & meter_at(superclock_t sc) const
static void init()
bool tempo_exists_before(TempoPoint const &t) const
Points::const_iterator get_grid(TempoMapPoints &points, superclock_t start, superclock_t end, uint32_t bar_mod=0, uint32_t beat_div=1) const
void fill_grid_with_final_metric(TempoMapPoints &ret, TempoMetric metric, superclock_t start, superclock_t rstart, superclock_t end, int bar_mod, int beat_div, Beats beats, BBT_Time bbt) const
bool move_tempo(TempoPoint const &point, timepos_t const &destination, bool push=false)
MeterPoint * add_meter(MeterPoint *)
uint32_t n_tempos() const
Beats quarters_at_superclock(superclock_t sc) const
bool solve_ramped_twist(TempoPoint &, TempoPoint &)
bool is_initial(MeterPoint const &) const
TempoPoint * add_tempo(TempoPoint *)
bool core_remove_tempo(TempoPoint const &)
bool tempo_exists_after(TempoPoint const &t) const
static thread_local SharedPtr _tempo_map_p
MeterPoint const & _meter_at(TimeType when, Comparator cmp) const
Beats quarters_at(timepos_t const &) const
MeterPoint const & meter_at(Beats const &b) const
bool can_remove(TempoPoint const &) const
BBT_Argument bbt_at(Beats const &) const
Beats bbtwalk_to_quarters(Beats const &start, BBT_Offset const &distance) const
void stretch_tempo(TempoPoint &ts, double new_npm)
MusicTimePoint * add_or_replace_bartime(MusicTimePoint *)
bool core_remove_bartime(MusicTimePoint const &)
bool solve_constant_twist(TempoPoint &, TempoPoint &)
void shift(timepos_t const &at, timecnt_t const &by)
static void update_thread_tempo_map()
TempoPoint * core_add_tempo(TempoPoint *, bool &)
static WritableSharedPtr write_copy()
void shift(timepos_t const &at, BBT_Offset const &by)
TempoMap(XMLNode const &, int version)
MusicTimes const & bartimes() const
TempoPoint const & tempo_at(superclock_t sc) const
void ramped_twist_tempi(TempoPoint &prev, TempoPoint &focus, TempoPoint &next, double tempo_delta)
Meter const * next_meter(Meter const &) const
int parse_meter_state_3x(const XMLNode &node, LegacyMeterState &lts)
samplepos_t sample_at(BBT_Argument const &b) const
MeterPoint * core_add_meter(MeterPoint *, bool &)
timecnt_t bbt_duration_at(timepos_t const &pos, BBT_Offset const &bbt) const
Beats scwalk_to_quarters(Beats const &pos, superclock_t distance) const
void remove_tempo(TempoPoint const &, bool with_reset=true)
TempoPoint const & _tempo_at(TimeType when, Comparator cmp) const
void remove_point(Point const &)
void dump(std::ostream &) const
uint32_t n_meters() const
TempoPoint & set_tempo(Tempo const &, timepos_t const &)
void reset_starting_at(Beats const &)
int set_state(XMLNode const &, int version)
void stretch_tempo_end(TempoPoint *ts, samplepos_t sample, samplepos_t end_sample)
Points::const_iterator get_tempo_and_meter(TempoPoint const *&t, MeterPoint const *&m, BBT_Argument const &bbt, bool can_match, bool ret_iterator_after_not_at) const
bool set_ramped(TempoPoint &, bool)
MeterPoint & set_meter(Meter const &, BBT_Argument const &)
MeterPoint const * previous_meter(MeterPoint const &) const
void remove_bartime(MusicTimePoint const &tp, bool with_reset=true)
samplepos_t sample_at(timepos_t const &t) const
TempoPoint const & tempo_at(Beats const &b) const
TempoPoint const * next_tempo(TempoPoint const &) const
int set_meters_from_state(XMLNode const &)
double min_notes_per_minute() const
void fill_grid_by_walking(TempoMapPoints &ret, Points::const_iterator &p, TempoMetric &metric, superclock_t &start, superclock_t rstart, superclock_t end, int bar_mod, int beat_div, Beats &beats, BBT_Time &bbt) const
bool remove_time(timepos_t const &pos, timecnt_t const &duration)
double max_notes_per_minute() const
constness_traits_t::iterator_type _get_tempo_and_meter(typename constness_traits_t::tempo_point_type &, typename constness_traits_t::meter_point_type &, typename constness_traits_t::time_reference(Point::*)() const, typename constness_traits_t::time_type, typename constness_traits_t::iterator_type begini, typename constness_traits_t::iterator_type endi, typename constness_traits_t::tempo_point_type tstart, typename constness_traits_t::meter_point_type mstart, bool can_match, bool ret_iterator_after_not_at) const
std::list< Point const * > Metrics
TempoMetric metric_at(timepos_t const &) const
int set_state_3x(XMLNode const &)
Meters const & meters() const
std::shared_ptr< TempoMap > WritableSharedPtr
BBT_Argument bbt_at(timepos_t const &) const
bool is_initial(TempoPoint const &) const
TempoPoint & set_tempo(Tempo const &t, timepos_t const &time, Beats const &beats)
void replace_bartime(MusicTimePoint &tp, bool with_reset=true)
superclock_t superclock_at(BBT_Argument const &) const
int set_music_times_from_state(XMLNode const &)
Points::const_iterator get_tempo_and_meter(TempoPoint const *&t, MeterPoint const *&m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) const
Beats quarters_at_sample(samplepos_t sc) const
TempoPoint const & tempo_at(BBT_Argument const &bbt) const
TempoMetric metric_at(superclock_t, bool can_match=true) const
void midi_clock_beat_at_or_after(samplepos_t const pos, samplepos_t &clk_pos, uint32_t &clk_beat) const
TempoMetric metric_at(BBT_Argument const &, bool can_match=true) const
superclock_t reftime(TempoPoint const &, MeterPoint const &) const
MusicTimePoint * core_add_bartime(MusicTimePoint *, bool &)
static int update(WritableSharedPtr m)
samplepos_t sample_at(Beats const &b) const
void get_metrics(Metrics &m) const
Beats bbtwalk_to_quarters(BBT_Argument const &start, BBT_Offset const &distance) const
void core_add_point(Point *)
void grid(TempoMapPoints &points, superclock_t start, superclock_t end, uint32_t bar_mod=0, uint32_t beat_div=1) const
static void set(SharedPtr new_map)
std::shared_ptr< TempoMap const > SharedPtr
TempoMap(Tempo const &initial_tempo, Meter const &initial_meter)
bool clear_tempos_after(timepos_t const &, bool stop_at_music_time)
MeterPoint & set_meter(Meter const &, superclock_t)
MeterPoint const * next_meter(MeterPoint const &) const
MeterPoint & set_meter(Meter const &, timepos_t const &)
XMLNode & get_state() const
void replace_tempo(TempoPoint const &old, Tempo const &thenew, timepos_t const &)
Points::iterator get_tempo_and_meter(TempoPoint *&t, MeterPoint *&m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at)
static PBD::Signal< void()> MapChanged
TempoPoint const * previous_tempo(TempoPoint const &) const
TempoMetric metric_at(Beats const &, bool can_match=true) const
BBT_Argument round_up_to_bar(BBT_Argument const &bbt) const
void reset_section(Points::iterator &begin, Points::iterator &end, superclock_t, TempoMetric &metric)
MeterPoint const & meter_at(BBT_Argument const &bbt) const
static SerializedRCUManager< TempoMap > _map_mgr
int set_tempos_from_state(XMLNode const &)
TempoPoint const & tempo_at(timepos_t const &p) const
double quarters_per_minute_at(timepos_t const &pos) const
Beats quarters_at(BBT_Argument const &) const
BBT_Argument round_to_bar(BBT_Argument const &bbt) const
TempoPoint & set_tempo(Tempo const &, BBT_Argument const &)
static SharedPtr fetch()
void get_grid(GridIterator &iter, TempoMapPoints &ret, superclock_t rstart, superclock_t end, uint32_t bar_mod=0, uint32_t beat_div=1) const
Tempos const & tempos() const
void change_tempo(TempoPoint &, Tempo const &)
TempoMap(TempoMap const &)
TempoMapCutBuffer * cut_copy(timepos_t const &start, timepos_t const &end, bool copy, bool ripple)
TempoMapCutBuffer * cut(timepos_t const &start, timepos_t const &end, bool ripple)
MeterPoint const & meter_at(timepos_t const &p) const
int parse_tempo_state_3x(const XMLNode &node, LegacyTempoState &lts)
void add_point(Point &)
Beats scwalk_to_quarters(superclock_t pos, superclock_t distance) const
superclock_t superclock_at(timepos_t const &) const
superclock_t superclock_at(Beats const &) const
bool can_remove(MeterPoint const &) const
static void map_assert(bool expr, char const *exprstr, char const *file, int line)
Points::const_iterator get_tempo_and_meter(TempoPoint const *&t, MeterPoint const *&m, Beats const &b, bool can_match, bool ret_iterator_after_not_at) const
bool core_remove_meter(MeterPoint const &)
TempoMapCutBuffer * copy(timepos_t const &start, timepos_t const &end)
Temporal::timecnt_t convert_duration(Temporal::timecnt_t const &duration, Temporal::timepos_t const &, Temporal::TimeDomain domain) const
bool move_meter(MeterPoint const &point, timepos_t const &destination, bool push=false)
BBT_Argument bbt_at(superclock_t sc) const
void reset_starting_at(superclock_t)
void paste(TempoMapCutBuffer const &, timepos_t const &position, bool ripple, std::string=std::string())
void set_bartime(BBT_Time const &, timepos_t const &, std::string name=std::string())
void sample_rate_changed(samplecnt_t new_sr)
bool clear_tempos_before(timepos_t const &, bool stop_at_music_time)
void constant_twist_tempi(TempoPoint &prev, TempoPoint &focus, TempoPoint &next, double tempo_delta)
TempoMap & operator=(TempoMap const &)
void remove_meter(MeterPoint const &, bool with_reset=true)
BBT_Argument bbt_walk(BBT_Argument const &, BBT_Offset const &) const
samplepos_t samples_per_bar(samplecnt_t sr) const
BBT_Argument round_up_to_bar(BBT_Time const &bbt) const
superclock_t superclock_at(Beats const &qn) const
samplepos_t sample_at(Beats const &qn) const
Beats quarters_at(BBT_Time const &bbt) const
TempoPoint const & tempo() const
BBT_Argument round_to_bar(BBT_Time const &bbt) const
MeterPoint const & meter() const
superclock_t superclocks_per_note_type_at_superclock(superclock_t sc) const
superclock_t superclocks_per_note_type() const
superclock_t superclock_at(BBT_Time const &) const
superclock_t superclocks_per_quarter_note() const
BBT_Argument bbt_add(BBT_Time const &bbt, BBT_Offset const &add) const
superclock_t superclocks_per_note_type(int note_type) const
BBT_Argument bbt_at(Beats const &beats) const
MeterPoint & get_editable_meter() const
BBT_Argument bbt_subtract(BBT_Time const &bbt, BBT_Offset const &sub) const
superclock_t end_superclocks_per_note_type() const
TempoMetric(TempoPoint const &t, MeterPoint const &m)
superclock_t superclocks_per_bar() const
Beats quarters_at_superclock(superclock_t sc) const
TempoPoint & get_editable_tempo() const
Beats quarters_at_sample(samplepos_t sc) const
BBT_Argument bbt_at(timepos_t const &) const
Beats to_quarters(BBT_Offset const &bbo) const
superclock_t superclocks_per_grid() const
superclock_t reftime() const
bool operator==(TempoPoint const &other) const
Beats quarters_at_sample(samplepos_t sc) const
samplepos_t sample_at(Beats const &qn) const
TempoPoint(TempoMap const &map, XMLNode const &)
void compute_omega_from_next_tempo(TempoPoint const &next_tempo)
superclock_t superclock_at(Beats const &qn) const
XMLNode & get_state() const
TempoPoint(Tempo const &t, Point const &p)
double note_types_per_minute_at_DOUBLE(timepos_t const &pos) const
bool operator!=(TempoPoint const &other) const
void compute_omega_from_quarter_duration(Beats const &quarter_duration, superclock_t end_scpqn)
void compute_omega_from_distance_and_next_tempo(Beats const &quarter_duration, TempoPoint const &next_tempo)
TempoPoint(TempoMap const &map, Tempo const &t, superclock_t sc, Beats const &b, BBT_Time const &bbt)
int set_state(XMLNode const &, int version)
void set_omega(double v)
Beats quarters_at_superclock(superclock_t sc) const
superclock_t superclocks_per_note_type_at(timepos_t const &) const
TempoPoint & operator=(Tempo const &t)
bool operator!=(Tempo const &other) const
Tempo(XMLNode const &)
double samples_per_quarter_note(int sr) const
void set_locked_to_meter(bool yn)
Tempo(double npm, double enpm, int8_t note_type)
double note_types_per_minute() const
superclock_t superclocks_per_quarter_note() const
superclock_t _superclocks_per_note_type
double end_note_types_per_minute() const
double samples_per_note_type(int sr) const
static std::string xml_node_name
superclock_t superclocks_per_note_type() const
int set_state(XMLNode const &, int version)
superclock_t end_superclocks_per_note_type() const
void set_end_npm(double)
bool operator==(Tempo const &other) const
double quarter_notes_per_minute() const
superclock_t superclocks_per_note_type(int note_type) const
void set_note_types_per_minute(double npm)
Tempo(double npm, int8_t note_type)
superclock_t end_superclocks_per_note_type(int note_type) const
superclock_t _end_superclocks_per_note_type
XMLNode & get_state() const
superclock_t end_superclocks_per_quarter_note() const
static superclock_t double_npm_to_scpn(double npm)
void set_continuing(bool yn)
static timepos_t from_superclock(superclock_t s)
Definition: timeline.h:73
Definition: xml++.h:114
GtkImageIconNameData name
Definition: gtkimage.h:6
PBD::PropertyDescriptor< timepos_t > start
Temporal::timepos_t timepos_t
void add(const Gtk::StockItem &item)
int64_t muldiv_round(int64_t v, int64_t n, int64_t d)
static superclock_t superclock_to_samples(superclock_t s, int sr)
Definition: superclock.h:48
boost::intrusive::list_base_hook< boost::intrusive::tag< struct point_tag > > point_hook
boost::intrusive::list_base_hook< boost::intrusive::tag< struct tempo_tag > > tempo_hook
std::vector< TempoMapPoint > TempoMapPoints
boost::intrusive::list< Point, boost::intrusive::base_hook< point_hook > > Points
boost::intrusive::list< TempoPoint, boost::intrusive::base_hook< tempo_hook > > Tempos
static superclock_t samples_to_superclock(int64_t samples, int sr)
Definition: superclock.h:49
static superclock_t superclock_ticks_per_second()
Definition: superclock.h:45
boost::intrusive::list_base_hook< boost::intrusive::tag< struct bartime_tag > > bartime_hook
boost::intrusive::list< MeterPoint, boost::intrusive::base_hook< meter_hook > > Meters
boost::intrusive::list_base_hook< boost::intrusive::tag< struct meterpoint_tag > > meter_hook
int64_t superclock_t
Definition: superclock.h:34
boost::intrusive::list< MusicTimePoint, boost::intrusive::base_hook< bartime_hook > > MusicTimes
void push(lua_State *L, T t)
Definition: LuaBridge.h:159
bool operator==(const ProcessorSelection &a, const ProcessorSelection &b)
superclock_t reference() const
Definition: bbt_argument.h:38
#define TEMPORAL_SAMPLE_RATE
Definition: superclock.h:58
#define LIBTEMPORAL_API