Ardour  9.0-rc2-38-g267efab6e8
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 class ScopedTempoMapOwner;
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; }
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 */
266  bool _continuing; /* true if our effective end tempo is defined
267  * by the following tempo in the TempoMap;
268  * false if we use our own end tempo. */
269 
270  static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second()); }
271 
272  protected:
273  friend class TempoMap;
274  void set_end_npm (double);
275 };
276 
279  public:
280 
281  static std::string xml_node_name;
282 
283  Meter (XMLNode const &);
284  Meter (int8_t dpb, int8_t nv) : _note_value (nv), _divisions_per_bar (dpb) {}
285  Meter (Meter const & other) : _note_value (other._note_value), _divisions_per_bar (other._divisions_per_bar) {}
286 
287  virtual ~Meter () {}
288 
289  int divisions_per_bar () const { return _divisions_per_bar; }
290  int note_value() const { return _note_value; }
291 
292  int32_t ticks_per_grid () const { return (4 * Beats::PPQN) / _note_value; }
293 
294  inline bool operator==(const Meter& other) const { return _divisions_per_bar == other.divisions_per_bar() && _note_value == other.note_value(); }
295  inline bool operator!=(const Meter& other) const { return _divisions_per_bar != other.divisions_per_bar() || _note_value != other.note_value(); }
296 
297  Meter& operator=(Meter const & other) {
298  if (&other != this) {
299  _divisions_per_bar = other._divisions_per_bar;
300  _note_value = other._note_value;
301  }
302  return *this;
303  }
304 
305  BBT_Offset bbt_delta (BBT_Time const & later, BBT_Time const &earlier) const;
306  BBT_Time bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const;
307  BBT_Time bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const;
308  BBT_Time round_to_bar (BBT_Time const &) const;
310  BBT_Time round_up_to_beat_div (BBT_Time const &, int beat_div) const;
311  BBT_Time round_up_to_beat (BBT_Time const & bbt) const { return round_up_to_beat_div (bbt, 1); }
312  BBT_Time round_to_beat (BBT_Time const &) const;
313  Beats to_quarters (BBT_Offset const &) const;
314 
315  Beats round_to_beat (Beats const &) const;
316 
317  XMLNode& get_state () const;
318  int set_state (XMLNode const&, int version);
319 
320  protected:
324  int8_t _note_value;
325  /* how many of '_note_value' make up a bar or measure */
327 };
328 
329 /* A MeterPoint is literally just the combination of a Meter with a Point
330  */
331 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct meterpoint_tag>> meter_hook;
332 class /*LIBTEMPORAL_API*/ MeterPoint : public Meter, public meter_hook, public virtual Point
333 {
334  public:
335  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) {}
337  LIBTEMPORAL_API MeterPoint (Meter const & m, Point const & p) : Point (p), Meter (m) {}
338 
339  virtual ~MeterPoint () {}
340 
343 
344  LIBTEMPORAL_API bool operator== (MeterPoint const & other) const {
345  return Meter::operator== (other) && Point::operator== (other);
346  }
347  LIBTEMPORAL_API bool operator!= (MeterPoint const & other) const {
348  return Meter::operator!= (other) || Point::operator!= (other);
349  }
350 
352 
353  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
354 };
355 
356 /* A TempoPoint is a combination of a Tempo with a Point. However, if the temp
357  * is ramped, then at some point we will need to compute the ramp coefficient
358  * (_omega) and store it so that we can compute tempo-at-time and
359  * time-at-quarter-note on demand.
360  */
361 
362 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct tempo_tag>> tempo_hook;
363 class /*LIBTEMPORAL_API*/ TempoPoint : public Tempo, public tempo_hook, public virtual Point
364 {
365  public:
366  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.) {}
367  LIBTEMPORAL_API TempoPoint (Tempo const & t, Point const & p) : Point (p), Tempo (t), _omega (0.) {}
369 
370  virtual ~TempoPoint () {}
371 
372  /* just change the tempo component, without moving */
374  *((Tempo*)this) = t;
375  return *this;
376  }
377 
378  /* Given that this tempo point controls tempo for the time indicated by
379  * the argument of the following 3 functions, return information about
380  * that time. The first 3 return convert between domains (with
381  * ::sample_at() just being a convenience function); the third returns
382  * information about the tempo at that time.
383  */
384 
388 
389  /* XXX at some point, we have had discussions about representing tempo
390  * as a rational number rather than a double. We have not reached that
391  * point yet (Nov 2021), and so at this point, this method is the
392  * canonical way to get "bpm at position" from a TempoPoint object.
393  */
394 
397  }
398 
399  LIBTEMPORAL_API double omega() const { return _omega; }
400 
402  LIBTEMPORAL_API void compute_omega_from_distance_and_next_tempo (Beats const & quarter_duration, TempoPoint const & next_tempo);
403  LIBTEMPORAL_API void compute_omega_from_quarter_duration (Beats const & quarter_duration, superclock_t end_scpqn);
404 
405  LIBTEMPORAL_API bool actually_ramped () const { return Tempo::ramped() && ( _omega != 0); /* do not need to check both omegas */ }
406 
408  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
409 
410  LIBTEMPORAL_API bool operator== (TempoPoint const & other) const {
411  return Tempo::operator== (other) && Point::operator== (other);
412  }
413  LIBTEMPORAL_API bool operator!= (TempoPoint const & other) const {
414  return Tempo::operator!= (other) || Point::operator!= (other);
415  }
416 
419 
420  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
421 
422  private:
423  double _omega;
424 
425  friend TempoMap;
426  void set_omega (double v);
427 };
428 
445 {
446  public:
447  TempoMetric (TempoPoint const & t, MeterPoint const & m);
448  virtual ~TempoMetric () {}
449 
450  superclock_t reftime() const { return _reftime; }
451 
452  TempoPoint const & tempo() const { return *_tempo; }
453  MeterPoint const & meter() const { return *_meter; }
454 
455  TempoPoint & get_editable_tempo() const { return *const_cast<TempoPoint*> (_tempo); }
456  MeterPoint & get_editable_meter() const { return *const_cast<MeterPoint*> (_meter); }
457 
458  /* even more convenient wrappers for individual aspects of a
459  * TempoMetric (i.e. just tempo or just meter information required
460  */
461 
462  superclock_t superclock_at (Beats const & qn) const { return _tempo->superclock_at (qn); }
463  samplepos_t sample_at (Beats const & qn) const { return _tempo->sample_at (qn); }
464  Beats quarters_at (BBT_Time const & bbt) const { return _meter->quarters_at (bbt); }
465  BBT_Argument bbt_at (Beats const & beats) const { return BBT_Argument (reftime(), _meter->bbt_at (beats)); }
466 
467  superclock_t superclocks_per_note_type () const { return _tempo->superclocks_per_note_type (); }
468  superclock_t end_superclocks_per_note_type () const {return _tempo->end_superclocks_per_note_type (); }
469  superclock_t superclocks_per_note_type (int note_type) const {return _tempo->superclocks_per_note_type (note_type); }
470  superclock_t superclocks_per_quarter_note () const {return _tempo->superclocks_per_quarter_note (); }
471 
472  int note_type () const { return _tempo->note_type(); }
473  int divisions_per_bar () const { return _meter->divisions_per_bar(); }
474  int note_value() const { return _meter->note_value(); }
475  BBT_Argument bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const { return BBT_Argument (reftime(), _meter->bbt_add (bbt, add)); }
476  BBT_Argument bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const { return BBT_Argument (reftime(), _meter->bbt_subtract (bbt, sub)); }
477  BBT_Argument round_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_to_bar (bbt)); }
478  BBT_Argument round_up_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_up_to_bar (bbt)); }
479  Beats to_quarters (BBT_Offset const & bbo) const { return _meter->to_quarters (bbo); }
480  Beats round_to_beat (Beats const & b) const { return _meter->round_to_beat (b); }
481 
482  /* combination methods that require both tempo and meter information */
483 
485  return superclocks_per_grid () * _meter->divisions_per_bar();
486  }
488  return PBD::muldiv_round (_tempo->superclocks_per_note_type(), _tempo->note_type(), (int64_t) _meter->note_value());
489  }
490 
492  if (!_tempo->actually_ramped()) {
493  return _tempo->superclocks_per_note_type ();
494  }
495  return _tempo->superclocks_per_note_type() * exp (-_tempo->omega() * (sc - _tempo->sclock()));
496  }
497 
498  BBT_Argument bbt_at (timepos_t const &) const;
501 
503  return superclock_to_samples (superclocks_per_bar (), sr);
504  }
505 
506  Beats quarters_at_sample (samplepos_t sc) const { return quarters_at_superclock (samples_to_superclock (sc, TEMPORAL_SAMPLE_RATE)); }
507  Beats quarters_at_superclock (superclock_t sc) const { return _tempo->quarters_at_superclock (sc); }
508 
509  protected:
513 
514 };
515 
516 /* A music time point is a place where BBT time is reset from
517  * whatever it would be when just inferring from the usual counting. Its
518  * position is given by a Point that might use superclock or Beats, and the
519  * Point's BBT time member is overwritten.
520  */
521 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct bartime_tag>> bartime_hook;
522 class /*LIBTEMPORAL_API*/ MusicTimePoint : public bartime_hook, public virtual TempoPoint, public virtual MeterPoint
523 {
524  public:
525  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())
526  : Point (map, sc, b, bbt), TempoPoint (t, *this), MeterPoint (m, *this), _name (name) {}
527 
529 
530  virtual ~MusicTimePoint () {}
531 
532  LIBTEMPORAL_API bool operator== (MusicTimePoint const & other) const {
533  return TempoPoint::operator== (other) && MeterPoint::operator== (other);
534  }
535 
537 
538  LIBTEMPORAL_API std::string name() const { return _name; }
539  LIBTEMPORAL_API void set_name (std::string const &);
540 
542 
543  private:
544  std::string _name;
545 };
546 
551 /* TempoMap concepts
552 
553  we have several different ways of talking about time:
554 
555  * PULSE : whole notes, just because. These are linearly related to any other
556  note type, so if you know a number of pulses (whole notes), you
557  know the corresponding number of any other note type (e.g. quarter
558  notes).
559 
560  * QUARTER NOTES : just what the name says. A lot of MIDI software and
561  concepts assume that a "beat" is a quarter-note.
562 
563  * BEAT : a fraction of a PULSE. Defined by the meter in effect, so requires
564  meter (time signature) information to convert to/from PULSE or QUARTER NOTES.
565  In a 5/8 time, a BEAT is 1/8th note. In a 4/4 time, a beat is quarter note.
566  This means that measuring time in BEATS is potentially non-linear (if
567  the time signature changes, there will be a different number of BEATS
568  corresponding to a given time in any other unit).
569 
570  * SUPERCLOCK : a very high resolution clock whose frequency
571  has as factors all common sample rates and all common note
572  type divisors. Related to MINUTES or SAMPLES only when a
573  sample rate is known. Related to PULSE or QUARTER NOTES only
574  when a tempo is known.
575 
576  * MINUTES : wallclock time measurement. related to SAMPLES or SUPERCLOCK
577  only when a sample rate is known.
578 
579 
580  * SAMPLES : audio time measurement. Related to MINUTES or SUPERCLOCK only
581  when a sample rate is known
582 
583  * BBT : bars|beats|ticks ... linearly related to BEATS but with the added
584  semantics of bars ("measures") added, in which beats are broken up
585  into groups of bars ("measures"). Requires meter (time signature)
586  information to compute to/from a given BEATS value. Contains no
587  additional time information compared to BEATS, but does have
588  additional semantic information.
589 
590  Nick sez: not every note onset is on a tick
591  Paul wonders: if it's 8 samples off, does it matter?
592  Nick sez: it should not phase with existing audio
593 
594  */
595 
597 {
598  public:
599  TempoMapPoint (TempoMap const & map, TempoMetric const & tm, superclock_t sc, Beats const & q, BBT_Time const & bbt)
600  : Point (map, sc, q, bbt), TempoMetric (tm) {}
602 
603  bool is_explicit_meter() const { return _meter->sclock() == sclock(); }
604  bool is_explicit_tempo() const { return _tempo->sclock() == sclock(); }
605  bool is_explicit_position() const { return false; }
606  bool is_explicit () const { return is_explicit_meter() || is_explicit_tempo() || is_explicit_position(); }
607 
608  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()); } }
609 };
610 
611 }
612 
613 namespace std {
614 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMapPoint const &);
615 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Tempo const &);
616 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Meter const &);
617 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Point const &);
618 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoPoint const &);
619 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MeterPoint const &);
620 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MusicTimePoint const &);
621 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMetric const &);
622 }
623 
624 namespace Temporal {
625 
626 typedef std::vector<TempoMapPoint> TempoMapPoints;
627 
628 typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
629 typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
630 typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
631 typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
632 
633 /* An object used to retain "position" across calls to get_grid()
634  */
636 {
637  public:
638  GridIterator () : sclock (0), tempo (nullptr), meter (nullptr), end (0), bar_mod (0), beat_div (1), valid (false), map (nullptr) {}
639  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,
640  uint32_t bmod, uint32_t bdiv)
641  : sclock (sc)
642  , beats (b)
643  , bbt (bb)
644  , tempo (tp)
645  , meter (mp)
646  , points_iterator (p)
647  , end (e)
648  , bar_mod (bmod)
649  , beat_div (bdiv)
650  , valid (false)
651  , map (&m)
652  {
653  valid = (tempo && meter);
654  }
655 
656  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,
657  uint32_t bmod, uint32_t bdiv) {
658  map = &m;
659  tempo = tp;
660  meter = mp;
661  sclock = sc;
662  beats = b;
663  bbt = bb;
664  points_iterator = p;
665  end = e;
666  bar_mod = bmod;
667  beat_div = bdiv;
668  }
669 
670  bool valid_for (TempoMap const & map, superclock_t start, uint32_t bar_mod, uint32_t beat_div) const;
671  void catch_up_to (superclock_t e) { end = e; }
672  void invalidate () { valid = false; }
673 
674 
675  /* These 3 members hold the position of the last discovered grid point */
679 
680  /* These 3 members hold the TempoMetric information that was in effect
681  * at the *end* of the last use of the GridIterator
682  */
683  TempoPoint const * tempo;
684  MeterPoint const * meter;
685 
686  /* the iterator in the tempo map's _points list that points to the next
687  * point to be considered, or _points.end()
688  */
689  Points::const_iterator points_iterator;
690 
691  /* The position of the end of the last use of the GridIterator. For the
692  iterator to be considered valid on the next call, the start must
693  match this value (see ::valid_for() above).
694  */
696 
697 
698  /* bar modulus and beat division used by GridIterator. These must match
699  the current call to ::get_grid() for the iterator to
700  be valid.
701  */
702 
703  uint32_t bar_mod;
704  uint32_t beat_div;
705 
706  private:
707  bool valid;
708 
709  TempoMap const * map; /* nullptr or the map instance this GridIterator
710  * was last used with.
711  */
712 };
713 
714 class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
715 {
716  /* Any given thread must be able to carry out tempo-related arithmetic
717  * and time domain conversions using a consistent version of a
718  * TempoMap. The map could be updated at any time, and for any reason
719  * (typically from a GUI thread), but some other thread could be
720  * using the map to convert from audio to music time (for example).
721  *
722  * We do not want to use locks for this - this math may happen in a
723  * realtime thread, and even worse, the lock may need to be held for
724  * long periods of time in order to have the desired effect: a thread
725  * may be performing some tempo-based arithmetic as part of a complex
726  * operation that requires multiple steps. The tempo map it uses must
727  * remain consistent across all steps, and so we would have to hold the
728  * lock across them all. That would create awkward and difficult
729  * semantics for map users - somewhat arbitrary rules about how long
730  * one could hold the map for, etc.
731  *
732  * Elsewhere in the codebase, we use RCU to solve this sort of
733  * issue. For example, if we need to operate on the current list of
734  * Routes, we get read-only copy of the list, and iterate over it,
735  * knowing that even if the canonical version is being changed, the
736  * copy we are using will not.
737  *
738  * However, the tempo map's use is often implicit rather than
739  * explicit. The callstack to convert between an audio domain time and
740  * a music domain time should not require passing a tempo map into
741  * every call.
742  *
743  * The approach taken here is to use a combination of RCU and
744  * thread-local variables. Any given thread is by definition ... single
745  * threaded. If the thread has a thread-local copy of a tempo map, it
746  * will not change except at explicit calls to change it. The tempo map
747  * can be accessed from any method executed by the thread. But the
748  * relationship between the thread-local copy and "actual" tempo map(s)
749  * is managed via RCU, meaning that read-only access is cheap (no
750  * actual copy required).
751  *
752  */
753  public:
754  typedef std::shared_ptr<TempoMap const> SharedPtr;
755  typedef std::shared_ptr<TempoMap> WritableSharedPtr;
756  private:
757  static thread_local SharedPtr _tempo_map_p;
759  static bool fetch_condition ();
760  public:
761  /* These are only for use in unit tests */
762  Points::size_type count_tempos_in_points() const;
763  Points::size_type count_meters_in_points() const;
764  public:
765  LIBTEMPORAL_API static void init ();
766 
768  LIBTEMPORAL_API static SharedPtr use() { assert (_tempo_map_p); return _tempo_map_p; }
770  /* No fetch condition for this, to be used only in association with LocalTempoMapScope */
771  LIBTEMPORAL_API static SharedPtr global_fetch() { return _map_mgr.reader(); }
772 
773  /* Used only by the ARDOUR::AudioEngine API to reset the process thread
774  * tempo map only when it has changed.
775  */
776 
777  LIBTEMPORAL_API static SharedPtr read() { return _map_mgr.reader(); }
778 
779  /* Because WritableSharedPtr can be implicitly cast to SharedPtr, this
780  * can be used on either a write_copy()'ed map, or one obtained via the
781  * RCU reader() method.
782  */
783  LIBTEMPORAL_API static void set (SharedPtr new_map) { _tempo_map_p = new_map; }
784 
785  /* API for typical tempo map changes */
786 
790 
791  /* not part of public API */
792  superclock_t reftime(TempoPoint const &, MeterPoint const &) const;
793 
794  /* and now on with the rest of the show ... */
795 
796  public:
798  LIBTEMPORAL_API TempoMap (Tempo const& initial_tempo, Meter const& initial_meter);
800  LIBTEMPORAL_API TempoMap (XMLNode const&, int version);
802 
803  /* For use ONLY when building a tempo map from an SMF tempo map */
808 
810 
812 
813  /* methods which modify the map. These must all be called using
814  * RCU-style semantics: get a writable copy, modify it, then update via
815  * the RCU manager.
816  */
817 
820 
822 
824 
825  LIBTEMPORAL_API void set_bartime (BBT_Time const &, timepos_t const &, std::string name = std::string());
826  LIBTEMPORAL_API void remove_bartime (MusicTimePoint const & tp, bool with_reset = true);
827  LIBTEMPORAL_API void replace_bartime (MusicTimePoint & tp, bool with_reset = true);
828 
830 
833 
834  LIBTEMPORAL_API void replace_tempo (TempoPoint const & old, Tempo const & thenew, timepos_t const &);
835 
838 
839  LIBTEMPORAL_API void remove_tempo (TempoPoint const &, bool with_reset = true);
840  LIBTEMPORAL_API void remove_meter (MeterPoint const &, bool with_reset = true);
841 
842  /* these are a convenience method that just wrap some odd semantics */
843  LIBTEMPORAL_API bool move_tempo (TempoPoint const & point, timepos_t const & destination, bool push = false);
844  LIBTEMPORAL_API bool move_meter (MeterPoint const & point, timepos_t const & destination, bool push = false);
845 
846  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
847 
848  LIBTEMPORAL_API void constant_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
849  LIBTEMPORAL_API void ramped_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
850 
851  LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm);
853 
854  LIBTEMPORAL_API bool clear_tempos_before (timepos_t const &, bool stop_at_music_time);
855  LIBTEMPORAL_API bool clear_tempos_after (timepos_t const &, bool stop_at_music_time);
856 
857  /* END OF MODIFYING METHODS */
858 
859  /* rather than giving direct access to the intrusive list members,
860  * offer one that uses an STL container instead.
861  */
862 
863  typedef std::list<Point const *> Metrics;
864 
865  void get_metrics (Metrics& m) const {
866  for (auto const & p : _points) {
867  m.push_back (&p);
868  }
869  }
870 
871  LIBTEMPORAL_API bool can_remove (TempoPoint const &) const;
872  LIBTEMPORAL_API bool can_remove (MeterPoint const &) const;
873 
874  LIBTEMPORAL_API bool is_initial (TempoPoint const &) const;
875  LIBTEMPORAL_API bool is_initial (MeterPoint const &) const;
876 
877  LIBTEMPORAL_API uint32_t n_meters() const;
878  LIBTEMPORAL_API uint32_t n_tempos() const;
879 
882 
885 
886  LIBTEMPORAL_API bool tempo_exists_before (TempoPoint const & t) const { return (bool) previous_tempo (t); }
887  LIBTEMPORAL_API bool tempo_exists_after (TempoPoint const & t) const { return (bool) next_tempo (t); }
888 
889  LIBTEMPORAL_API Meter const* next_meter (Meter const &) const;
890 
892 
893  /* These return the TempoMetric in effect at the given time. If
894  can_match is true, then the TempoMetric may refer to a Tempo or
895  Meter at the given time. If can_match is false, the TempoMetric will
896  only refer to the Tempo or Metric preceding the given time.
897  */
898  LIBTEMPORAL_API TempoMetric metric_at (Beats const &, bool can_match = true) const;
899  LIBTEMPORAL_API TempoMetric metric_at (BBT_Argument const &, bool can_match = true) const;
900 
901  LIBTEMPORAL_API TempoMapCutBuffer* cut (timepos_t const & start, timepos_t const & end, bool ripple);
903  LIBTEMPORAL_API void paste (TempoMapCutBuffer const &, timepos_t const & position, bool ripple, std::string = std::string());
904 
905  LIBTEMPORAL_API void shift (timepos_t const & at, BBT_Offset const & by);
906  LIBTEMPORAL_API void shift (timepos_t const & at, timecnt_t const & by);
907 
909 
910  private:
911  template<typename TimeType, typename Comparator> TempoPoint const & _tempo_at (TimeType when, Comparator cmp) const {
912  assert (!_tempos.empty());
913 
914  if (_tempos.size() == 1) {
915  return _tempos.front();
916  }
917 
918  Tempos::const_iterator prev = _tempos.end();
919  for (Tempos::const_iterator t = _tempos.begin(); t != _tempos.end(); ++t) {
920  if (cmp (*t, when)) {
921  prev = t;
922  } else {
923  break;
924  }
925  }
926  if (prev == _tempos.end()) {
927  return _tempos.front();
928  }
929  return *prev;
930  }
931 
932  template<typename TimeType, typename Comparator> MeterPoint const & _meter_at (TimeType when, Comparator cmp) const {
933  assert (!_meters.empty());
934 
935  if (_meters.size() == 1) {
936  return _meters.front();
937  }
938 
939  Meters::const_iterator prev = _meters.end();
940  for (Meters::const_iterator m = _meters.begin(); m != _meters.end(); ++m) {
941  if (cmp (*m, when)) {
942  prev = m;
943  } else {
944  break;
945  }
946  }
947  if (prev == _meters.end()) {
948  return _meters.front();
949  }
950  return *prev;
951  }
952 
953  public:
954  LIBTEMPORAL_API MeterPoint const& meter_at (timepos_t const & p) const;
956  LIBTEMPORAL_API MeterPoint const& meter_at (Beats const & b) const { return _meter_at (b, Point::beat_comparator()); }
957  LIBTEMPORAL_API MeterPoint const& meter_at (BBT_Argument const & bbt) const { return _meter_at (bbt, Point::bbt_comparator()); }
958 
959  LIBTEMPORAL_API TempoPoint const& tempo_at (timepos_t const & p) const;
961  LIBTEMPORAL_API TempoPoint const& tempo_at (Beats const & b) const { return _tempo_at (b, Point::beat_comparator()); }
962  LIBTEMPORAL_API TempoPoint const& tempo_at (BBT_Argument const & bbt) const { return _tempo_at (bbt, Point::bbt_comparator()); }
963 
966 
967  /* convenience function that hides some complexities behind fetching
968  * the bpm at position
969  */
971 
972  /* convenience functions */
974  return metric_at (bbt).round_to_bar (bbt);
975  }
977  return metric_at (bbt).round_up_to_bar (bbt);
978  }
979 
982 
985 
989 
993 
994  /* ways to walk along the tempo map, measure distance between points,
995  * etc.
996  */
997 
1000 
1002  LIBTEMPORAL_API Beats bbtwalk_to_quarters (Beats const & start, BBT_Offset const & distance) const;
1004 
1006 
1008 
1010 
1011  Tempos const & tempos() const { return _tempos; }
1012  Meters const & meters() const { return _meters; }
1013  MusicTimes const & bartimes() const { return _bartimes; }
1014 
1015 
1016  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;
1017  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;
1018 
1019  /* This version exists for Lua bindings, to avoid having to wrap Points::iterator etc. */
1020  LIBTEMPORAL_API void grid (TempoMapPoints& points, superclock_t start, superclock_t end, uint32_t bar_mod = 0, uint32_t beat_div = 1) const {
1021  get_grid (points, start, end, bar_mod, beat_div);
1022  }
1023 
1024  struct EmptyTempoMapException : public std::exception {
1025  virtual const char* what() const throw() { return "TempoMap is empty"; }
1026  };
1027 
1028  LIBTEMPORAL_API void dump (std::ostream&) const;
1029 
1031 
1033 
1036 
1037  LIBTEMPORAL_API void midi_clock_beat_at_or_after (samplepos_t const pos, samplepos_t& clk_pos, uint32_t& clk_beat) const;
1038 
1039  static void map_assert (bool expr, char const * exprstr, char const * file, int line);
1040 
1044 
1045  private:
1051 
1055 
1060 
1062 
1066 
1067  void add_point (Point &);
1068 
1069  void reset_starting_at (superclock_t, bool constant_bbt = true);
1070  void reset_starting_at (Beats const &);
1071 
1072  void remove_point (Point const &);
1073 
1074  void copy_points (TempoMap const & other);
1075 
1077 
1078  template<typename T, typename T1> struct const_traits {
1079  typedef Points::const_iterator iterator_type;
1080  typedef TempoPoint const * tempo_point_type;
1081  typedef MeterPoint const * meter_point_type;
1082  using time_reference = T;
1083  using time_type = T1;
1084  };
1085 
1086  template<typename T, typename T1> struct non_const_traits {
1087  typedef Points::iterator iterator_type;
1090  using time_reference = T;
1091  using time_type = T1;
1092  };
1093 
1094  /* A somewhat complex method that sets a TempoPoint* and MeterPoint* to
1095  * refer to the correct tempo and meter points for the given start
1096  * time.
1097  *
1098  * It also returns an iterator which may point at the latter of the two
1099  * points (tempo & meter; always the meter point if they are at the
1100  * same time) OR may point at the iterator *after* the latter of the
1101  * two, depending on whether or not @p ret_iterator_after_not_at is
1102  * true or false.
1103  *
1104  * If @p can_match is true, the points used can be located at the
1105  * given time. If false, they must be before it. Setting it to false is
1106  * useful when you need to know the TempoMetric in effect at a given
1107  * time if there was no tempo or meter point at that time.
1108  *
1109  * The templated structure here is to avoid code duplication in 2
1110  * separate versions of this method, one that would be const, and one
1111  * that would be non-const. This is a challenging problem in C++, and
1112  * seems best solved by using a "traits" object as shown here.
1113  *
1114  * The begini, endi, tstart and mstart arguments are an additional
1115  * complication. If we try to use e.g. _points.begin() inside the
1116  * method, which is labelled const, we will always get the const
1117  * version of the iterator. This const iterator type will conflict with
1118  * the non-const iterator type defined by the "non_const_traits"
1119  * type. The same happens with _tempos.front() etc. This problem is
1120  * addressed by calling these methods in the caller method, which maybe
1121  * const or non-const, and will provide appropriate versions based on that.
1122  */
1123 
1124  template<class constness_traits_t> typename constness_traits_t::iterator_type
1125  _get_tempo_and_meter (typename constness_traits_t::tempo_point_type &,
1126  typename constness_traits_t::meter_point_type &,
1127  typename constness_traits_t::time_reference (Point::*)() const,
1128  typename constness_traits_t::time_type,
1129  typename constness_traits_t::iterator_type begini,
1130  typename constness_traits_t::iterator_type endi,
1131  typename constness_traits_t::tempo_point_type tstart,
1132  typename constness_traits_t::meter_point_type mstart,
1133  bool can_match,
1134  bool ret_iterator_after_not_at) const;
1135 
1136  /* fetch non-const tempo/meter pairs and iterator (used in
1137  * ::reset_starting_at() in which we will modify points.
1138  */
1139 
1140  Points::iterator get_tempo_and_meter (TempoPoint *& t, MeterPoint *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) {
1141 
1142  /* because `this` is non-const (because the method is not
1143  * marked const), the following:
1144 
1145  _points.begin()
1146  _points.end()
1147  _tempos.front()
1148  _meters.front()
1149 
1150  will all be the non-const versions of these methods.
1151  */
1152 
1153  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1154  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);
1155  }
1156 
1157  /* fetch const tempo/meter pairs and iterator (used in metric_at() and
1158  * other similar call sites where we do not modify the map
1159  */
1160 
1161  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 {
1162  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1163  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);
1164  }
1165  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 {
1166  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1167  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);
1168  }
1169 
1170  Points::const_iterator get_tempo_and_meter_bbt (TempoPoint const *& t, MeterPoint const *& m, BBT_Argument const & bbt, bool can_match, bool ret_iterator_after_not_at) const;
1171 
1172  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 {
1173  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1174  return get_tempo_and_meter_bbt (t, m, bbt, can_match, ret_iterator_after_not_at);
1175  }
1176 
1177  /* This is private, and should not be callable from outside the map
1178  because of potential confusion between samplepos_t and
1179  superclock_t. The timepos_t variant of ::metric_at() handles any
1180  samplepos_t-passing call.
1181  */
1182  TempoMetric metric_at (superclock_t, bool can_match = true) const;
1183 
1184  /* parsing legacy tempo maps */
1185 
1187  {
1189  double pulses;
1192  double note_type;
1193  bool continuing; /* "clamped" in actual legacy stuff */
1194  };
1195 
1197  {
1199  double pulses;
1201  double beat;
1203  double note_type;
1204  };
1205 
1208  int set_state_3x (XMLNode const &);
1209  TempoPoint & set_tempo (Tempo const & t, timepos_t const & time, Beats const & beats);
1210 
1211  friend class TempoPoint;
1212  friend class MeterPoint;
1213  friend class TempoMetric;
1214 
1215  bool solve_ramped_twist (TempoPoint&, TempoPoint&); /* this is implemented by iteration, and it might fail. */
1216  bool solve_constant_twist (TempoPoint&, TempoPoint&); //TODO: currently also done by iteration; should be possible to calculate directly
1217 
1221 
1222  void reset_section (Points::iterator& begin, superclock_t, TempoMetric& metric, bool constant_bbt);
1223 
1224  TempoMapCutBuffer* cut_copy (timepos_t const & start, timepos_t const & end, bool copy, bool ripple);
1225 
1226  void fill_grid_by_walking (TempoMapPoints& ret, Points::const_iterator& p, TempoMetric& metric, superclock_t& start, superclock_t rstart,
1227  superclock_t end, int bar_mod, int beat_div, Beats& beats, BBT_Time& bbt) const;
1228  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;
1229 };
1230 
1232 {
1233  public:
1236 
1237  timecnt_t duration() const { return _duration; }
1238 
1239  void add_start_tempo (Tempo const & t);
1240  void add_end_tempo (Tempo const & t);
1241  void add_start_meter (Meter const & t);
1242  void add_end_meter (Meter const & t);
1243 
1244  Tempo const * start_tempo () const { return _start_tempo; }
1245  Tempo const * end_tempo () const { return _end_tempo; }
1246 
1247  Meter const * start_meter () const { return _start_meter; }
1248  Meter const * end_meter () const { return _end_meter; }
1249 
1250  typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
1251  typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
1252  typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
1253  typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
1254 
1255  void add (TempoPoint const &);
1256  void add (MeterPoint const &);
1257  void add (MusicTimePoint const &);
1258  void add (Point const &);
1259 
1260  void clear ();
1261  void dump (std::ostream&);
1262 
1263  Tempos const & tempos() const { return _tempos; }
1264  Meters const & meters() const { return _meters; }
1265  MusicTimes const & bartimes() const { return _bartimes; }
1266  Points const & points() const { return _points; }
1267 
1268  bool empty() const {
1269  return _tempos.empty() && _meters.empty() && _bartimes.empty() && _points.empty();
1270  }
1271 
1272  private:
1278 
1283 };
1284 
1286  public:
1287 
1288  TempoCommand (std::string const & name, XMLNode const * before, XMLNode const * after);
1291 
1292  const std::string& name () const { return _name; }
1293 
1294  void operator() ();
1295  void undo ();
1296 
1297  XMLNode & get_state () const;
1298 
1299  protected:
1300  std::string _name;
1301  XMLNode const * _before;
1302  XMLNode const * _after;
1303 };
1304 
1305 } /* end of namespace Temporal */
1306 
1307 #ifdef COMPILER_MSVC
1308 #pragma warning(disable:4101)
1309 #endif
std::ostream & operator<<(std::ostream &o, ARDOUR::Bundle const &)
static const int32_t PPQN
Definition: beats.h:67
Beats round_to_beat() const
Definition: beats.h:130
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_Offset bbt_delta(BBT_Time const &later, BBT_Time const &earlier) const
Beats round_to_beat(Beats const &) 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
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
samplepos_t sample_is_dangerous(int sr) 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_tempo_and_meter_bbt(TempoPoint const *&t, MeterPoint const *&m, BBT_Argument const &bbt, bool can_match, bool ret_iterator_after_not_at) 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 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
Points::size_type count_meters_in_points() 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 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 &)
ScopedTempoMapOwner * scope_owner() const
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 &)
Point * core_remove_bartime(MusicTimePoint const &)
void reset_starting_at(Beats const &)
void reset_section(Points::iterator &begin, superclock_t, TempoMetric &metric, bool constant_bbt)
int set_state(XMLNode const &, int version)
Point * core_remove_meter(MeterPoint const &)
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
BBT_Offset bbt_distance(BBT_Argument const &a, BBT_Argument const &b) 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
void smf_add(TempoPoint &)
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
void reset_starting_at(superclock_t, bool constant_bbt=true)
superclock_t reftime(TempoPoint const &, MeterPoint const &) const
static SharedPtr global_fetch()
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 set_scope_owner(ScopedTempoMapOwner &)
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
MeterPoint const & meter_at(BBT_Argument const &bbt) const
static SerializedRCUManager< TempoMap > _map_mgr
int set_tempos_from_state(XMLNode const &)
static bool fetch_condition()
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
Point * core_remove_tempo(TempoPoint 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
timepos_t duration(TimeDomain) const
void smf_add(MeterPoint &)
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
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)
Points::size_type count_tempos_in_points() const
superclock_t previous_bbt_reference_at_superclock(superclock_t) const
BBT_Argument bbt_at(superclock_t sc) const
ScopedTempoMapOwner * _scope_owner
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
BBT_Argument bbt_at_superclock(superclock_t) 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
Beats round_to_beat(Beats const &b) 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)
#define TEMPORAL_SAMPLE_RATE
Definition: superclock.h:58
#define LIBTEMPORAL_API