Ardour  9.7-99-gdb2953b2e4
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 "pbd/command.h"
31 #include "pbd/enum_convert.h"
32 #include "pbd/integer_division.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/rcu.h"
35 #include "pbd/signals.h"
37 
38 #include "temporal/visibility.h"
39 #include "temporal/beats.h"
40 #include "temporal/bbt_argument.h"
41 #include "temporal/bbt_time.h"
42 #include "temporal/domain_swap.h"
43 #include "temporal/superclock.h"
44 #include "temporal/timeline.h"
45 #include "temporal/types.h"
46 
47 /* A tempo map is built from 3 types of entities
48 
49  1) tempo markers
50  2) meter (time signature) markers
51  3) position markers
52 
53  Beats increase monotonically throughout the tempo map (BBT may not).
54 
55  The map has a single time domain at any time.
56 */
57 
58 namespace Temporal {
59 
60 class Meter;
61 class TempoMap;
62 class TempoMapCutBuffer;
63 class ScopedTempoMapOwner;
64 
65 class MapOwned {
66  protected:
67  MapOwned (TempoMap const & map) : _map (&map) {}
68  virtual ~MapOwned () {}
69 
70  public:
71  TempoMap const & map() const { return *_map; }
72 
73  protected:
74  friend class TempoMap;
75  void set_map (TempoMap const & map) { _map = &map; }
76  TempoMap const * _map;
77 };
78 
79 /* Conceptually, Point is similar to timepos_t. However, whereas timepos_t can
80  * use the TempoMap to translate between time domains, Point cannot. Why not?
81  * Because Point is foundational in building the tempo map, and we cannot
82  * create a circular functional dependency between them. So a Point always has
83  * its superclock and beat time defined and no translation between them is possible.
84  */
85 
86 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct point_tag>> point_hook;
87 class /*LIBTEMPORAL_API*/ Point : public point_hook, public MapOwned {
88  public:
89  LIBTEMPORAL_API Point (TempoMap const & map, superclock_t sc, Beats const & b, BBT_Time const & bbt) : MapOwned (map), _sclock (sc), _quarters (b), _bbt (bbt) {}
91 
92  LIBTEMPORAL_API virtual ~Point() {}
93 
94  LIBTEMPORAL_API void set (superclock_t sc, Beats const & b, BBT_Time const & bbt) {
95  _sclock = sc;
96  _quarters = b;
97  _bbt = bbt;
98  }
99 
101  LIBTEMPORAL_API Beats const & beats() const { return _quarters; }
102  LIBTEMPORAL_API BBT_Time const & bbt() const { return _bbt; }
104 
105  LIBTEMPORAL_API virtual timepos_t time() const = 0;
106 
108  bool operator() (Point const & a, Point const & b) const {
109  return a.sclock() < b.sclock();
110  }
111  bool operator() (Point const & a, superclock_t sc) const {
112  return a.sclock() < sc;
113  }
114  };
115 
117  bool operator() (Point const * a, Point const * b) const {
118  return a->sclock() < b->sclock();
119  }
120  };
121 
123  bool operator() (Point const & a, Point const & b) const {
124  return a.beats() < b.beats();
125  }
126  bool operator() (Point const & a, Beats const & beats) const {
127  return a.beats() < beats;
128  }
129  };
130 
132  bool operator() (Point const & a, Point const & b) const {
133  return a.bbt() < b.bbt();
134  }
135  bool operator() (Point const & a, BBT_Time const & bbt) const {
136  return a.bbt() < bbt;
137  }
138  };
139 
140  /* all time members are supposed to be synced at all times, so we need
141  test only one.
142  */
143  LIBTEMPORAL_API inline bool operator== (Point const & other) const { return _sclock == other._sclock; }
144  LIBTEMPORAL_API inline bool operator!= (Point const & other) const { return _sclock != other._sclock; }
145 
146  protected:
150 
151  void add_state (XMLNode &) const;
152 
153  protected:
154  friend class TempoMap;
156 };
157 
162  public:
163  enum Type {
165  Constant
166  };
167 
168  static std::string xml_node_name;
169 
170  Tempo (XMLNode const &);
171  virtual ~Tempo () {}
172 
177  Tempo (double npm, uint8_t note_type)
178  : _npm (npm)
179  , _enpm (npm)
180  , _superclocks_per_note_type (double_npm_to_scpn (npm))
181  , _end_superclocks_per_note_type (double_npm_to_scpn (npm))
182  , _note_type (note_type)
183  , _locked_to_meter (false)
184  , _continuing (false)
185  {}
186 
187  Tempo (double npm, double enpm, int8_t note_type)
188  : _npm (npm)
189  , _enpm (npm)
190  , _superclocks_per_note_type (double_npm_to_scpn (npm))
191  , _end_superclocks_per_note_type (double_npm_to_scpn (enpm))
192  , _note_type (note_type)
193  , _locked_to_meter (false)
194  , _continuing (false)
195  {}
196 
197  /* these five methods should only be used to show and collect information to the user (for whom
198  * bpm as a floating point number is the obvious representation)
199  */
200  double note_types_per_minute () const { return ((double) superclock_ticks_per_second() * 60.0) / (double) _superclocks_per_note_type; }
201  double end_note_types_per_minute () const { return ((double) superclock_ticks_per_second() * 60.0) / (double) _end_superclocks_per_note_type; }
202  double quarter_notes_per_minute() const { return ((double) superclock_ticks_per_second() * 60.0 * 4.0) / (_note_type * (double) _superclocks_per_note_type); }
203  double samples_per_note_type(int sr) const { return superclock_to_samples (superclocks_per_note_type (), sr); }
204  double samples_per_quarter_note(int sr) const { return superclock_to_samples (superclocks_per_quarter_note(), sr); }
205 
206  void set_note_types_per_minute (double npm);
207 
208  int note_type () const { return _note_type; }
209 
211  return _superclocks_per_note_type;
212  }
213  superclock_t superclocks_per_note_type (int note_type) const {
214  return (_superclocks_per_note_type * _note_type) / note_type;
215  }
217  return superclocks_per_note_type (4);
218  }
220  return _end_superclocks_per_note_type;
221  }
223  return (_end_superclocks_per_note_type * _note_type) / note_type;
224  }
226  return end_superclocks_per_note_type (4);
227  }
228 
229  bool locked_to_meter () const { return _locked_to_meter; }
230  void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
231 
232  bool continuing() const { return _continuing; }
233  void set_continuing (bool yn);
234 
235  Type type() const { return _superclocks_per_note_type == _end_superclocks_per_note_type ? Constant : Ramped; }
236  bool ramped () const { return _superclocks_per_note_type != _end_superclocks_per_note_type; }
237 
238  XMLNode& get_state () const;
239  int set_state (XMLNode const&, int version);
240 
241  bool operator== (Tempo const & other) const {
242  return _superclocks_per_note_type == other._superclocks_per_note_type &&
243  _end_superclocks_per_note_type == other._end_superclocks_per_note_type &&
244  _note_type == other._note_type &&
245  _locked_to_meter == other._locked_to_meter &&
246  _continuing == other._continuing;
247  }
248 
249  bool operator!= (Tempo const & other) const {
250  return _superclocks_per_note_type != other._superclocks_per_note_type ||
251  _end_superclocks_per_note_type != other._end_superclocks_per_note_type ||
252  _note_type != other._note_type ||
253  _locked_to_meter != other._locked_to_meter ||
254  _continuing != other._continuing;
255  }
256 
257  protected:
258  double _npm;
259  double _enpm;
262  uint8_t _note_type;
263  bool _locked_to_meter; /* XXX name has unclear meaning with nutempo */
264  bool _continuing; /* true if our effective end tempo is defined
265  * by the following tempo in the TempoMap;
266  * false if we use our own end tempo. */
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_Offset bbt_delta (BBT_Time const & later, BBT_Time const &earlier) const;
304  BBT_Time bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const;
305  BBT_Time bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const;
306  BBT_Time round_to_bar (BBT_Time const &) const;
308  BBT_Time round_up_to_beat_div (BBT_Time const &, int beat_div) const;
309  BBT_Time round_up_to_beat (BBT_Time const & bbt) const { return round_up_to_beat_div (bbt, 1); }
310  BBT_Time round_to_beat (BBT_Time const &) const;
311  Beats to_quarters (BBT_Offset const &) const;
312 
313  Beats round_to_beat (Beats const &) const;
314 
315  XMLNode& get_state () const;
316  int set_state (XMLNode const&, int version);
317 
318  protected:
322  int8_t _note_value;
323  /* how many of '_note_value' make up a bar or measure */
325 };
326 
327 /* A MeterPoint is literally just the combination of a Meter with a Point
328  */
329 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct meterpoint_tag>> meter_hook;
330 class /*LIBTEMPORAL_API*/ MeterPoint : public Meter, public meter_hook, public virtual Point
331 {
332  public:
333  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) {}
335  LIBTEMPORAL_API MeterPoint (Meter const & m, Point const & p) : Point (p), Meter (m) {}
336 
337  virtual ~MeterPoint () {}
338 
341 
342  LIBTEMPORAL_API bool operator== (MeterPoint const & other) const {
343  return Meter::operator== (other) && Point::operator== (other);
344  }
345  LIBTEMPORAL_API bool operator!= (MeterPoint const & other) const {
346  return Meter::operator!= (other) || Point::operator!= (other);
347  }
348 
350 
351  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
352 };
353 
354 /* A TempoPoint is a combination of a Tempo with a Point. However, if the temp
355  * is ramped, then at some point we will need to compute the ramp coefficient
356  * (_omega) and store it so that we can compute tempo-at-time and
357  * time-at-quarter-note on demand.
358  */
359 
360 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct tempo_tag>> tempo_hook;
361 class /*LIBTEMPORAL_API*/ TempoPoint : public Tempo, public tempo_hook, public virtual Point
362 {
363  public:
364  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.) {}
365  LIBTEMPORAL_API TempoPoint (Tempo const & t, Point const & p) : Point (p), Tempo (t), _omega (0.) {}
367 
368  virtual ~TempoPoint () {}
369 
370  /* just change the tempo component, without moving */
372  *((Tempo*)this) = t;
373  return *this;
374  }
375 
376  /* Given that this tempo point controls tempo for the time indicated by
377  * the argument of the following 3 functions, return information about
378  * that time. The first 3 return convert between domains (with
379  * ::sample_at() just being a convenience function); the third returns
380  * information about the tempo at that time.
381  */
382 
386 
387  /* XXX at some point, we have had discussions about representing tempo
388  * as a rational number rather than a double. We have not reached that
389  * point yet (Nov 2021), and so at this point, this method is the
390  * canonical way to get "bpm at position" from a TempoPoint object.
391  */
392 
395  }
396 
397  LIBTEMPORAL_API double omega() const { return _omega; }
398 
400  LIBTEMPORAL_API void compute_omega_from_distance_and_next_tempo (Beats const & quarter_duration, TempoPoint const & next_tempo);
401  LIBTEMPORAL_API void compute_omega_from_quarter_duration (Beats const & quarter_duration, superclock_t end_scpqn);
402 
403  LIBTEMPORAL_API bool actually_ramped () const { return Tempo::ramped() && ( _omega != 0); /* do not need to check both omegas */ }
404 
406  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
407 
408  LIBTEMPORAL_API bool operator== (TempoPoint const & other) const {
409  return Tempo::operator== (other) && Point::operator== (other);
410  }
411  LIBTEMPORAL_API bool operator!= (TempoPoint const & other) const {
412  return Tempo::operator!= (other) || Point::operator!= (other);
413  }
414 
417 
418  LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
419 
420  private:
421  double _omega;
422 
423  friend TempoMap;
424  void set_omega (double v);
425 };
426 
443 {
444  public:
445  TempoMetric (TempoPoint const & t, MeterPoint const & m);
446  virtual ~TempoMetric () {}
447 
448  superclock_t reftime() const { return _reftime; }
449 
450  TempoPoint const & tempo() const { return *_tempo; }
451  MeterPoint const & meter() const { return *_meter; }
452 
453  TempoPoint & get_editable_tempo() const { return *const_cast<TempoPoint*> (_tempo); }
454  MeterPoint & get_editable_meter() const { return *const_cast<MeterPoint*> (_meter); }
455 
456  /* even more convenient wrappers for individual aspects of a
457  * TempoMetric (i.e. just tempo or just meter information required
458  */
459 
460  superclock_t superclock_at (Beats const & qn) const { return _tempo->superclock_at (qn); }
461  samplepos_t sample_at (Beats const & qn) const { return _tempo->sample_at (qn); }
462  Beats quarters_at (BBT_Time const & bbt) const;
463  BBT_Argument bbt_at (Beats const & beats) const { return BBT_Argument (reftime(), _meter->bbt_at (beats)); }
464 
465  superclock_t superclocks_per_note_type () const { return _tempo->superclocks_per_note_type (); }
466  superclock_t end_superclocks_per_note_type () const {return _tempo->end_superclocks_per_note_type (); }
467  superclock_t superclocks_per_note_type (int note_type) const {return _tempo->superclocks_per_note_type (note_type); }
468  superclock_t superclocks_per_quarter_note () const {return _tempo->superclocks_per_quarter_note (); }
469 
470  int note_type () const { return _tempo->note_type(); }
471  int divisions_per_bar () const { return _meter->divisions_per_bar(); }
472  int note_value() const { return _meter->note_value(); }
473  BBT_Argument bbt_add (BBT_Time const & bbt, BBT_Offset const & add) const { return BBT_Argument (reftime(), _meter->bbt_add (bbt, add)); }
474  BBT_Argument bbt_subtract (BBT_Time const & bbt, BBT_Offset const & sub) const { return BBT_Argument (reftime(), _meter->bbt_subtract (bbt, sub)); }
475  BBT_Argument round_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_to_bar (bbt)); }
476  BBT_Argument round_up_to_bar (BBT_Time const & bbt) const { return BBT_Argument (reftime(), _meter->round_up_to_bar (bbt)); }
477  Beats to_quarters (BBT_Offset const & bbo) const { return _meter->to_quarters (bbo); }
478  Beats round_to_beat (Beats const & b) const { return _meter->round_to_beat (b); }
479 
480  /* combination methods that require both tempo and meter information */
481 
483  return superclocks_per_grid () * _meter->divisions_per_bar();
484  }
486  return PBD::muldiv_round (_tempo->superclocks_per_note_type(), _tempo->note_type(), (int64_t) _meter->note_value());
487  }
488 
490  if (!_tempo->actually_ramped()) {
491  return _tempo->superclocks_per_note_type ();
492  }
493  return _tempo->superclocks_per_note_type() * exp (-_tempo->omega() * (sc - _tempo->sclock()));
494  }
495 
496  BBT_Argument bbt_at (timepos_t const &) const;
499 
501  return superclock_to_samples (superclocks_per_bar (), sr);
502  }
503 
504  Beats quarters_at_sample (samplepos_t sc) const { return quarters_at_superclock (samples_to_superclock (sc, TEMPORAL_SAMPLE_RATE)); }
505  Beats quarters_at_superclock (superclock_t sc) const { return _tempo->quarters_at_superclock (sc); }
506 
507  protected:
511 
512 };
513 
514 /* A music time point is a place where BBT time is reset from
515  * whatever it would be when just inferring from the usual counting. Its
516  * position is given by a Point that might use superclock or Beats, and the
517  * Point's BBT time member is overwritten.
518  */
519 typedef boost::intrusive::list_base_hook<boost::intrusive::tag<struct bartime_tag>> bartime_hook;
520 class /*LIBTEMPORAL_API*/ MusicTimePoint : public bartime_hook, public virtual TempoPoint, public virtual MeterPoint
521 {
522  public:
523  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())
524  : Point (map, sc, b, bbt), TempoPoint (t, *this), MeterPoint (m, *this), _name (name) {}
525 
527 
528  virtual ~MusicTimePoint () {}
529 
530  LIBTEMPORAL_API bool operator== (MusicTimePoint const & other) const {
531  return TempoPoint::operator== (other) && MeterPoint::operator== (other);
532  }
533 
535 
536  LIBTEMPORAL_API std::string name() const { return _name; }
537  LIBTEMPORAL_API void set_name (std::string const &);
538 
540 
541  private:
542  std::string _name;
543 };
544 
549 /* TempoMap concepts
550 
551  we have several different ways of talking about time:
552 
553  * PULSE : whole notes, just because. These are linearly related to any other
554  note type, so if you know a number of pulses (whole notes), you
555  know the corresponding number of any other note type (e.g. quarter
556  notes).
557 
558  * QUARTER NOTES : just what the name says. A lot of MIDI software and
559  concepts assume that a "beat" is a quarter-note.
560 
561  * BEAT : a fraction of a PULSE. Defined by the meter in effect, so requires
562  meter (time signature) information to convert to/from PULSE or QUARTER NOTES.
563  In a 5/8 time, a BEAT is 1/8th note. In a 4/4 time, a beat is quarter note.
564  This means that measuring time in BEATS is potentially non-linear (if
565  the time signature changes, there will be a different number of BEATS
566  corresponding to a given time in any other unit).
567 
568  * SUPERCLOCK : a very high resolution clock whose frequency
569  has as factors all common sample rates and all common note
570  type divisors. Related to MINUTES or SAMPLES only when a
571  sample rate is known. Related to PULSE or QUARTER NOTES only
572  when a tempo is known.
573 
574  * MINUTES : wallclock time measurement. related to SAMPLES or SUPERCLOCK
575  only when a sample rate is known.
576 
577 
578  * SAMPLES : audio time measurement. Related to MINUTES or SUPERCLOCK only
579  when a sample rate is known
580 
581  * BBT : bars|beats|ticks ... linearly related to BEATS but with the added
582  semantics of bars ("measures") added, in which beats are broken up
583  into groups of bars ("measures"). Requires meter (time signature)
584  information to compute to/from a given BEATS value. Contains no
585  additional time information compared to BEATS, but does have
586  additional semantic information.
587 
588  Nick sez: not every note onset is on a tick
589  Paul wonders: if it's 8 samples off, does it matter?
590  Nick sez: it should not phase with existing audio
591 
592  */
593 
595 {
596  public:
597  TempoMapPoint (TempoMap const & map, TempoMetric const & tm, superclock_t sc, Beats const & q, BBT_Time const & bbt)
598  : Point (map, sc, q, bbt), TempoMetric (tm) {}
600 
601  bool is_explicit_meter() const { return _meter->sclock() == sclock(); }
602  bool is_explicit_tempo() const { return _tempo->sclock() == sclock(); }
603  bool is_explicit_position() const { return false; }
604  bool is_explicit () const { return is_explicit_meter() || is_explicit_tempo() || is_explicit_position(); }
605 
606  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()); } }
607 };
608 
609 }
610 
611 namespace std {
612 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMapPoint const &);
613 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Tempo const &);
614 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Meter const &);
615 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::Point const &);
616 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoPoint const &);
617 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MeterPoint const &);
618 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::MusicTimePoint const &);
619 LIBTEMPORAL_API std::ostream& operator<<(std::ostream& str, Temporal::TempoMetric const &);
620 }
621 
622 namespace Temporal {
623 
624 typedef std::vector<TempoMapPoint> TempoMapPoints;
625 
626 typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
627 typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
628 typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
629 typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
630 
631 /* An object used to retain "position" across calls to get_grid()
632  */
634 {
635  public:
636  GridIterator () : sclock (0), tempo (nullptr), meter (nullptr), end (0), bar_mod (0), beat_div (1), valid (false), map (nullptr) {}
637  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,
638  uint32_t bmod, uint32_t bdiv)
639  : sclock (sc)
640  , beats (b)
641  , bbt (bb)
642  , tempo (tp)
643  , meter (mp)
644  , points_iterator (p)
645  , end (e)
646  , bar_mod (bmod)
647  , beat_div (bdiv)
648  , valid (false)
649  , map (&m)
650  {
651  valid = (tempo && meter);
652  }
653 
654  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,
655  uint32_t bmod, uint32_t bdiv) {
656  map = &m;
657  tempo = tp;
658  meter = mp;
659  sclock = sc;
660  beats = b;
661  bbt = bb;
662  points_iterator = p;
663  end = e;
664  bar_mod = bmod;
665  beat_div = bdiv;
666  }
667 
668  bool valid_for (TempoMap const & map, superclock_t start, uint32_t bar_mod, uint32_t beat_div) const;
669  void catch_up_to (superclock_t e) { end = e; }
670  void invalidate () { valid = false; }
671 
672 
673  /* These 3 members hold the position of the last discovered grid point */
677 
678  /* These 3 members hold the TempoMetric information that was in effect
679  * at the *end* of the last use of the GridIterator
680  */
681  TempoPoint const * tempo;
682  MeterPoint const * meter;
683 
684  /* the iterator in the tempo map's _points list that points to the next
685  * point to be considered, or _points.end()
686  */
687  Points::const_iterator points_iterator;
688 
689  /* The position of the end of the last use of the GridIterator. For the
690  iterator to be considered valid on the next call, the start must
691  match this value (see ::valid_for() above).
692  */
694 
695 
696  /* bar modulus and beat division used by GridIterator. These must match
697  the current call to ::get_grid() for the iterator to
698  be valid.
699  */
700 
701  uint32_t bar_mod;
702  uint32_t beat_div;
703 
704  private:
705  bool valid;
706 
707  TempoMap const * map; /* nullptr or the map instance this GridIterator
708  * was last used with.
709  */
710 };
711 
712 class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
713 {
714  /* Any given thread must be able to carry out tempo-related arithmetic
715  * and time domain conversions using a consistent version of a
716  * TempoMap. The map could be updated at any time, and for any reason
717  * (typically from a GUI thread), but some other thread could be
718  * using the map to convert from audio to music time (for example).
719  *
720  * We do not want to use locks for this - this math may happen in a
721  * realtime thread, and even worse, the lock may need to be held for
722  * long periods of time in order to have the desired effect: a thread
723  * may be performing some tempo-based arithmetic as part of a complex
724  * operation that requires multiple steps. The tempo map it uses must
725  * remain consistent across all steps, and so we would have to hold the
726  * lock across them all. That would create awkward and difficult
727  * semantics for map users - somewhat arbitrary rules about how long
728  * one could hold the map for, etc.
729  *
730  * Elsewhere in the codebase, we use RCU to solve this sort of
731  * issue. For example, if we need to operate on the current list of
732  * Routes, we get read-only copy of the list, and iterate over it,
733  * knowing that even if the canonical version is being changed, the
734  * copy we are using will not.
735  *
736  * However, the tempo map's use is often implicit rather than
737  * explicit. The callstack to convert between an audio domain time and
738  * a music domain time should not require passing a tempo map into
739  * every call.
740  *
741  * The approach taken here is to use a combination of RCU and
742  * thread-local variables. Any given thread is by definition ... single
743  * threaded. If the thread has a thread-local copy of a tempo map, it
744  * will not change except at explicit calls to change it. The tempo map
745  * can be accessed from any method executed by the thread. But the
746  * relationship between the thread-local copy and "actual" tempo map(s)
747  * is managed via RCU, meaning that read-only access is cheap (no
748  * actual copy required).
749  *
750  */
751  public:
752  typedef std::shared_ptr<TempoMap const> SharedPtr;
753  typedef std::shared_ptr<TempoMap> WritableSharedPtr;
754  private:
755  static thread_local SharedPtr _tempo_map_p;
756 #ifdef MINGW_NATIVE_TLS
757  /* Due to Native TLS recently being added, errors come from
758  thread_local variables during external linkage.
759  See https://github.com/msys2/MINGW-packages/issues/29272 */
760  static LIBTEMPORAL_API SharedPtr& _tempo_map_ref ();
761 #endif
763  static bool fetch_condition ();
764  public:
765  /* These are only for use in unit tests */
766  Points::size_type count_tempos_in_points() const;
767  Points::size_type count_meters_in_points() const;
768  public:
769  LIBTEMPORAL_API static void init ();
770 
771 #ifndef MINGW_NATIVE_TLS
773  LIBTEMPORAL_API static SharedPtr use() { assert (_tempo_map_p); return _tempo_map_p; }
775 #else
776  LIBTEMPORAL_API static void update_thread_tempo_map() { _tempo_map_ref() = _map_mgr.reader(); }
777  LIBTEMPORAL_API static SharedPtr use() { assert (_tempo_map_ref()); return _tempo_map_ref(); }
778  LIBTEMPORAL_API static SharedPtr fetch() { assert (fetch_condition()); update_thread_tempo_map(); return _tempo_map_ref(); }
779 #endif
780  /* No fetch condition for this, to be used only in association with LocalTempoMapScope */
781  LIBTEMPORAL_API static SharedPtr global_fetch() { return _map_mgr.reader(); }
782 
783  /* Used only by the ARDOUR::AudioEngine API to reset the process thread
784  * tempo map only when it has changed.
785  */
786 
787  LIBTEMPORAL_API static SharedPtr read() { return _map_mgr.reader(); }
788 
789  /* Because WritableSharedPtr can be implicitly cast to SharedPtr, this
790  * can be used on either a write_copy()'ed map, or one obtained via the
791  * RCU reader() method.
792  */
793 #ifndef MINGW_NATIVE_TLS
794  LIBTEMPORAL_API static void set (SharedPtr new_map) { _tempo_map_p = new_map; }
795 #else
796  LIBTEMPORAL_API static void set (SharedPtr new_map) { _tempo_map_ref() = new_map; }
797 #endif
798 
799  /* API for typical tempo map changes */
800 
804 
805  /* not part of public API */
806  superclock_t reftime(TempoPoint const &, MeterPoint const &) const;
807 
808  /* and now on with the rest of the show ... */
809 
810  public:
812  LIBTEMPORAL_API TempoMap (Tempo const& initial_tempo, Meter const& initial_meter);
814  LIBTEMPORAL_API TempoMap (XMLNode const&, int version);
816 
817  /* For use ONLY when building a tempo map from an SMF tempo map */
822 
824 
826 
827  /* methods which modify the map. These must all be called using
828  * RCU-style semantics: get a writable copy, modify it, then update via
829  * the RCU manager.
830  */
831 
834 
836 
838 
839  LIBTEMPORAL_API void set_bartime (BBT_Time const &, timepos_t const &, std::string name = std::string());
840  LIBTEMPORAL_API void remove_bartime (MusicTimePoint const & tp, bool with_reset = true);
841  LIBTEMPORAL_API void replace_bartime (MusicTimePoint & tp, bool with_reset = true);
842 
844 
847 
848  LIBTEMPORAL_API void replace_tempo (TempoPoint const & old, Tempo const & thenew, timepos_t const &);
849 
852 
853  LIBTEMPORAL_API void remove_tempo (TempoPoint const &, bool with_reset = true);
854  LIBTEMPORAL_API void remove_meter (MeterPoint const &, bool with_reset = true);
855 
856  /* these are a convenience method that just wrap some odd semantics */
857  LIBTEMPORAL_API bool move_tempo (TempoPoint const & point, timepos_t const & destination, bool push = false);
858  LIBTEMPORAL_API bool move_meter (MeterPoint const & point, timepos_t const & destination, bool push = false);
859 
860  LIBTEMPORAL_API int set_state (XMLNode const&, int version);
861 
862  LIBTEMPORAL_API void constant_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
863  LIBTEMPORAL_API void ramped_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
864 
865  LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm);
867 
868  LIBTEMPORAL_API bool clear_tempos_before (timepos_t const &, bool stop_at_music_time);
869  LIBTEMPORAL_API bool clear_tempos_after (timepos_t const &, bool stop_at_music_time);
870 
871  /* END OF MODIFYING METHODS */
872 
873  /* rather than giving direct access to the intrusive list members,
874  * offer one that uses an STL container instead.
875  */
876 
877  typedef std::list<Point const *> Metrics;
878 
879  void get_metrics (Metrics& m) const {
880  for (auto const & p : _points) {
881  m.push_back (&p);
882  }
883  }
884 
885  LIBTEMPORAL_API bool can_remove (TempoPoint const &) const;
886  LIBTEMPORAL_API bool can_remove (MeterPoint const &) const;
887 
888  LIBTEMPORAL_API bool is_initial (TempoPoint const &) const;
889  LIBTEMPORAL_API bool is_initial (MeterPoint const &) const;
890 
891  LIBTEMPORAL_API uint32_t n_meters() const;
892  LIBTEMPORAL_API uint32_t n_tempos() const;
893 
896 
899 
900  LIBTEMPORAL_API bool tempo_exists_before (TempoPoint const & t) const { return (bool) previous_tempo (t); }
901  LIBTEMPORAL_API bool tempo_exists_after (TempoPoint const & t) const { return (bool) next_tempo (t); }
902 
903  LIBTEMPORAL_API Meter const* next_meter (Meter const &) const;
904 
906 
907  /* These return the TempoMetric in effect at the given time. If
908  can_match is true, then the TempoMetric may refer to a Tempo or
909  Meter at the given time. If can_match is false, the TempoMetric will
910  only refer to the Tempo or Metric preceding the given time.
911  */
912  LIBTEMPORAL_API TempoMetric metric_at (Beats const &, bool can_match = true) const;
913  LIBTEMPORAL_API TempoMetric metric_at (BBT_Argument const &, bool can_match = true) const;
914 
915  LIBTEMPORAL_API TempoMapCutBuffer* cut (timepos_t const & start, timepos_t const & end, bool ripple);
917  LIBTEMPORAL_API void paste (TempoMapCutBuffer const &, timepos_t const & position, bool ripple, std::string = std::string(), bool with_bbt_marker = true);
918 
919  LIBTEMPORAL_API void shift (timepos_t const & at, BBT_Offset const & by);
920  LIBTEMPORAL_API void shift (timepos_t const & at, timecnt_t const & by);
921 
923 
924  private:
925  template<typename TimeType, typename Comparator> TempoPoint const & _tempo_at (TimeType when, Comparator cmp) const {
926  assert (!_tempos.empty());
927 
928  if (_tempos.size() == 1) {
929  return _tempos.front();
930  }
931 
932  Tempos::const_iterator prev = _tempos.end();
933  for (Tempos::const_iterator t = _tempos.begin(); t != _tempos.end(); ++t) {
934  if (cmp (*t, when)) {
935  prev = t;
936  } else {
937  break;
938  }
939  }
940  if (prev == _tempos.end()) {
941  return _tempos.front();
942  }
943  return *prev;
944  }
945 
946  template<typename TimeType, typename Comparator> MeterPoint const & _meter_at (TimeType when, Comparator cmp) const {
947  assert (!_meters.empty());
948 
949  if (_meters.size() == 1) {
950  return _meters.front();
951  }
952 
953  Meters::const_iterator prev = _meters.end();
954  for (Meters::const_iterator m = _meters.begin(); m != _meters.end(); ++m) {
955  if (cmp (*m, when)) {
956  prev = m;
957  } else {
958  break;
959  }
960  }
961  if (prev == _meters.end()) {
962  return _meters.front();
963  }
964  return *prev;
965  }
966 
967  public:
968  LIBTEMPORAL_API MeterPoint const& meter_at (timepos_t const & p) const;
970  LIBTEMPORAL_API MeterPoint const& meter_at (Beats const & b) const { return _meter_at (b, Point::beat_comparator()); }
971  LIBTEMPORAL_API MeterPoint const& meter_at (BBT_Argument const & bbt) const { return _meter_at (bbt, Point::bbt_comparator()); }
972 
973  LIBTEMPORAL_API TempoPoint const& tempo_at (timepos_t const & p) const;
975  LIBTEMPORAL_API TempoPoint const& tempo_at (Beats const & b) const { return _tempo_at (b, Point::beat_comparator()); }
976  LIBTEMPORAL_API TempoPoint const& tempo_at (BBT_Argument const & bbt) const { return _tempo_at (bbt, Point::bbt_comparator()); }
977 
980 
981  /* convenience function that hides some complexities behind fetching
982  * the bpm at position
983  */
985 
986  /* convenience functions */
988  return metric_at (bbt).round_to_bar (bbt);
989  }
991  return metric_at (bbt).round_up_to_bar (bbt);
992  }
993 
996 
999 
1003 
1007 
1008  /* ways to walk along the tempo map, measure distance between points,
1009  * etc.
1010  */
1011 
1014 
1016  LIBTEMPORAL_API Beats bbtwalk_to_quarters (Beats const & start, BBT_Offset const & distance) const;
1018 
1020 
1022 
1024 
1025  Tempos const & tempos() const { return _tempos; }
1026  Meters const & meters() const { return _meters; }
1027  MusicTimes const & bartimes() const { return _bartimes; }
1028 
1029 
1030  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;
1031  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;
1032 
1033  /* This version exists for Lua bindings, to avoid having to wrap Points::iterator etc. */
1034  LIBTEMPORAL_API void grid (TempoMapPoints& points, superclock_t start, superclock_t end, uint32_t bar_mod = 0, uint32_t beat_div = 1) const {
1035  get_grid (points, start, end, bar_mod, beat_div);
1036  }
1037 
1038  struct EmptyTempoMapException : public std::exception {
1039  virtual const char* what() const throw() { return "TempoMap is empty"; }
1040  };
1041 
1042  LIBTEMPORAL_API void dump (std::ostream&) const;
1043 
1045 
1047 
1050 
1051  LIBTEMPORAL_API void midi_clock_beat_at_or_after (samplepos_t const pos, samplepos_t& clk_pos, uint32_t& clk_beat) const;
1052 
1053  static void map_assert (bool expr, char const * exprstr, char const * file, int line);
1054 
1058 
1059  private:
1065 
1069 
1074 
1076 
1080 
1081  void add_point (Point &);
1082 
1083  void reset_starting_at (superclock_t, bool constant_bbt = true);
1084  void reset_starting_at (Beats const &);
1085 
1086  void remove_point (Point const &);
1087 
1088  void copy_points (TempoMap const & other);
1089 
1091 
1092  template<typename T, typename T1> struct const_traits {
1093  typedef Points::const_iterator iterator_type;
1094  typedef TempoPoint const * tempo_point_type;
1095  typedef MeterPoint const * meter_point_type;
1096  using time_reference = T;
1097  using time_type = T1;
1098  };
1099 
1100  template<typename T, typename T1> struct non_const_traits {
1101  typedef Points::iterator iterator_type;
1104  using time_reference = T;
1105  using time_type = T1;
1106  };
1107 
1108  /* A somewhat complex method that sets a TempoPoint* and MeterPoint* to
1109  * refer to the correct tempo and meter points for the given start
1110  * time.
1111  *
1112  * It also returns an iterator which may point at the latter of the two
1113  * points (tempo & meter; always the meter point if they are at the
1114  * same time) OR may point at the iterator *after* the latter of the
1115  * two, depending on whether or not @p ret_iterator_after_not_at is
1116  * true or false.
1117  *
1118  * If @p can_match is true, the points used can be located at the
1119  * given time. If false, they must be before it. Setting it to false is
1120  * useful when you need to know the TempoMetric in effect at a given
1121  * time if there was no tempo or meter point at that time.
1122  *
1123  * The templated structure here is to avoid code duplication in 2
1124  * separate versions of this method, one that would be const, and one
1125  * that would be non-const. This is a challenging problem in C++, and
1126  * seems best solved by using a "traits" object as shown here.
1127  *
1128  * The begini, endi, tstart and mstart arguments are an additional
1129  * complication. If we try to use e.g. _points.begin() inside the
1130  * method, which is labelled const, we will always get the const
1131  * version of the iterator. This const iterator type will conflict with
1132  * the non-const iterator type defined by the "non_const_traits"
1133  * type. The same happens with _tempos.front() etc. This problem is
1134  * addressed by calling these methods in the caller method, which maybe
1135  * const or non-const, and will provide appropriate versions based on that.
1136  */
1137 
1138  template<class constness_traits_t> typename constness_traits_t::iterator_type
1139  _get_tempo_and_meter (typename constness_traits_t::tempo_point_type &,
1140  typename constness_traits_t::meter_point_type &,
1141  typename constness_traits_t::time_reference (Point::*)() const,
1142  typename constness_traits_t::time_type,
1143  typename constness_traits_t::iterator_type begini,
1144  typename constness_traits_t::iterator_type endi,
1145  typename constness_traits_t::tempo_point_type tstart,
1146  typename constness_traits_t::meter_point_type mstart,
1147  bool can_match,
1148  bool ret_iterator_after_not_at) const;
1149 
1150  /* fetch non-const tempo/meter pairs and iterator (used in
1151  * ::reset_starting_at() in which we will modify points.
1152  */
1153 
1154  Points::iterator get_tempo_and_meter (TempoPoint *& t, MeterPoint *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) {
1155 
1156  /* because `this` is non-const (because the method is not
1157  * marked const), the following:
1158 
1159  _points.begin()
1160  _points.end()
1161  _tempos.front()
1162  _meters.front()
1163 
1164  will all be the non-const versions of these methods.
1165  */
1166 
1167  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1168  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);
1169  }
1170 
1171  /* fetch const tempo/meter pairs and iterator (used in metric_at() and
1172  * other similar call sites where we do not modify the map
1173  */
1174 
1175  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 {
1176  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1177  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);
1178  }
1179  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 {
1180  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1181  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);
1182  }
1183 
1184  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;
1185 
1186  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 {
1187  if (_tempos.size() == 1 && _meters.size() == 1) { t = &_tempos.front(); m = &_meters.front(); return _points.end(); }
1188  return get_tempo_and_meter_bbt (t, m, bbt, can_match, ret_iterator_after_not_at);
1189  }
1190 
1191  /* This is private, and should not be callable from outside the map
1192  because of potential confusion between samplepos_t and
1193  superclock_t. The timepos_t variant of ::metric_at() handles any
1194  samplepos_t-passing call.
1195  */
1196  TempoMetric metric_at (superclock_t, bool can_match = true) const;
1197 
1198  /* parsing legacy tempo maps */
1199 
1201  {
1203  double pulses;
1206  double note_type;
1207  bool continuing; /* "clamped" in actual legacy stuff */
1208  };
1209 
1211  {
1213  double pulses;
1215  double beat;
1217  double note_type;
1218  };
1219 
1222  int set_state_3x (XMLNode const &);
1223  TempoPoint & set_tempo (Tempo const & t, timepos_t const & time, Beats const & beats);
1224 
1225  friend class TempoPoint;
1226  friend class MeterPoint;
1227  friend class TempoMetric;
1228 
1229  bool solve_ramped_twist (TempoPoint&, TempoPoint&); /* this is implemented by iteration, and it might fail. */
1230  bool solve_constant_twist (TempoPoint&, TempoPoint&); //TODO: currently also done by iteration; should be possible to calculate directly
1231 
1235 
1236  void reset_section (Points::iterator& begin, superclock_t, TempoMetric& metric, bool constant_bbt);
1237 
1238  TempoMapCutBuffer* cut_copy (timepos_t const & start, timepos_t const & end, bool copy, bool ripple);
1239 
1240  void fill_grid_by_walking (TempoMapPoints& ret, Points::const_iterator& p, TempoMetric& metric, superclock_t& start, superclock_t rstart,
1241  superclock_t end, int bar_mod, int beat_div, Beats& beats, BBT_Time& bbt) const;
1242  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;
1243 };
1244 
1246 {
1247  public:
1250 
1251  timecnt_t duration() const { return _duration; }
1252 
1253  void add_start_tempo (Tempo const & t);
1254  void add_end_tempo (Tempo const & t);
1255  void add_start_meter (Meter const & t);
1256  void add_end_meter (Meter const & t);
1257 
1258  Tempo const * start_tempo () const { return _start_tempo; }
1259  Tempo const * end_tempo () const { return _end_tempo; }
1260 
1261  Meter const * start_meter () const { return _start_meter; }
1262  Meter const * end_meter () const { return _end_meter; }
1263 
1264  typedef boost::intrusive::list<TempoPoint, boost::intrusive::base_hook<tempo_hook>> Tempos;
1265  typedef boost::intrusive::list<MeterPoint, boost::intrusive::base_hook<meter_hook>> Meters;
1266  typedef boost::intrusive::list<MusicTimePoint, boost::intrusive::base_hook<bartime_hook>> MusicTimes;
1267  typedef boost::intrusive::list<Point, boost::intrusive::base_hook<point_hook>> Points;
1268 
1269  void add (TempoPoint const &);
1270  void add (MeterPoint const &);
1271  void add (MusicTimePoint const &);
1272  void add (Point const &);
1273 
1274  void clear ();
1275  void dump (std::ostream&);
1276 
1277  Tempos const & tempos() const { return _tempos; }
1278  Meters const & meters() const { return _meters; }
1279  MusicTimes const & bartimes() const { return _bartimes; }
1280  Points const & points() const { return _points; }
1281 
1282  bool empty() const {
1283  return _tempos.empty() && _meters.empty() && _bartimes.empty() && _points.empty();
1284  }
1285 
1286  private:
1292 
1297 };
1298 
1300  public:
1301 
1302  TempoCommand (std::string const & name, XMLNode const * before, XMLNode const * after);
1305 
1306  const std::string& name () const { return _name; }
1307 
1308  void operator() ();
1309  void undo ();
1310 
1311  XMLNode & get_state () const;
1312 
1313  protected:
1314  std::string _name;
1315  XMLNode const * _before;
1316  XMLNode const * _after;
1317 };
1318 
1319 } /* end of namespace Temporal */
1320 
1321 #ifdef COMPILER_MSVC
1322 #pragma warning(disable:4101)
1323 #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
void paste(TempoMapCutBuffer const &, timepos_t const &position, bool ripple, std::string=std::string(), bool with_bbt_marker=true)
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 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
Tempo(double npm, uint8_t note_type)
superclock_t superclocks_per_note_type(int note_type) const
void set_note_types_per_minute(double npm)
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