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