13
0

temporal: remove the concept of a time domain for the tempo map

TempoPoint and MeterPoint always have their position set in musical time; MusicTimePoint (BBT)
always has a position in audio time. It's that simple
This commit is contained in:
Paul Davis 2022-05-23 14:24:34 -06:00
parent bd3fdaeb67
commit e3501a05f8
3 changed files with 53 additions and 243 deletions

View File

@ -2121,13 +2121,7 @@ Session::flush_cue_recording ()
BBT_Time bbt = tmap->bbt_at (timepos_t (cr.when)); BBT_Time bbt = tmap->bbt_at (timepos_t (cr.when));
bbt = bbt.round_up_to_bar (); bbt = bbt.round_up_to_bar ();
timepos_t when; const timepos_t when (tmap->quarters_at (bbt));
if (tmap->time_domain() == Temporal::AudioTime) {
when = timepos_t (tmap->sample_at (bbt));
} else {
when = timepos_t (tmap->quarters_at (bbt));
}
Location* l = new Location (*this, when, when, std::string(), Location::Flags (Location::IsMark|Location::IsCueMarker), cr.cue_number); Location* l = new Location (*this, when, when, std::string(), Location::Flags (Location::IsMark|Location::IsCueMarker), cr.cue_number);
_locations->add (l); _locations->add (l);

View File

@ -79,16 +79,6 @@ Point::sample() const
} }
#endif #endif
timepos_t
Point::time() const
{
if (_map->time_domain() == AudioTime) {
return timepos_t::from_superclock (sclock());
}
return timepos_t (beats());
}
Tempo::Tempo (XMLNode const & node) Tempo::Tempo (XMLNode const & node)
{ {
assert (node.name() == xml_node_name); assert (node.name() == xml_node_name);
@ -701,7 +691,6 @@ TempoMapPoint::end_float ()
/* TEMPOMAP */ /* TEMPOMAP */
TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter) TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter)
: _time_domain (AudioTime)
{ {
TempoPoint* tp = new TempoPoint (*this, initial_tempo, 0, Beats(), BBT_Time()); TempoPoint* tp = new TempoPoint (*this, initial_tempo, 0, Beats(), BBT_Time());
MeterPoint* mp = new MeterPoint (*this, initial_meter, 0, Beats(), BBT_Time()); MeterPoint* mp = new MeterPoint (*this, initial_meter, 0, Beats(), BBT_Time());
@ -723,7 +712,6 @@ TempoMap::TempoMap (XMLNode const & node, int version)
} }
TempoMap::TempoMap (TempoMap const & other) TempoMap::TempoMap (TempoMap const & other)
: _time_domain (other.time_domain())
{ {
copy_points (other); copy_points (other);
} }
@ -731,7 +719,6 @@ TempoMap::TempoMap (TempoMap const & other)
TempoMap& TempoMap&
TempoMap::operator= (TempoMap const & other) TempoMap::operator= (TempoMap const & other)
{ {
_time_domain = other.time_domain();
copy_points (other); copy_points (other);
return *this; return *this;
} }
@ -768,38 +755,6 @@ TempoMap::copy_points (TempoMap const & other)
} }
} }
void
TempoMap::set_time_domain (TimeDomain td)
{
if (td == time_domain()) {
return;
}
#warning paul tempo_map::set_time_domain needs implementing
#if 0
switch (td) {
case AudioTime:
for (Tempos::iterator t = _tempos.begin(); t != _tempos.end(); ++t) {
t->set_sclock (t->superclock_at (t->beats ()));
}
for (Meters::iterator m = _meters.begin(); m != _meters.end(); ++m) {
m->set_sclock (m->superclock_at (m->beats ()));
}
break;
default:
for (Tempos::iterator t = _tempos.begin(); t != _tempos.end(); ++t) {
t->set_beats (t->quarters_at_superclock (t->sclock()));
}
for (Meters::iterator m = _meters.begin(); m != _meters.end(); ++m) {
m->set_beats (m->quarters_at_superclock (m->sclock()));
}
}
#endif
_time_domain = td;
}
MeterPoint* MeterPoint*
TempoMap::add_meter (MeterPoint* mp) TempoMap::add_meter (MeterPoint* mp)
{ {
@ -808,16 +763,8 @@ TempoMap::add_meter (MeterPoint* mp)
const superclock_t sclock_limit = mp->sclock(); const superclock_t sclock_limit = mp->sclock();
const Beats beats_limit = mp->beats (); const Beats beats_limit = mp->beats ();
switch (time_domain()) { for (m = _meters.begin(); m != _meters.end() && m->beats() < beats_limit; ++m);
case AudioTime: for (p = _points.begin(); p != _points.end() && p->beats() < beats_limit; ++p);
for (m = _meters.begin(); m != _meters.end() && m->sclock() < sclock_limit; ++m);
for (p = _points.begin(); p != _points.end() && p->sclock() < sclock_limit; ++p);
break;
case BeatTime:
for (m = _meters.begin(); m != _meters.end() && m->beats() < beats_limit; ++m);
for (p = _points.begin(); p != _points.end() && p->beats() < beats_limit; ++p);
break;
}
bool replaced = false; bool replaced = false;
MeterPoint* ret = 0; MeterPoint* ret = 0;
@ -917,16 +864,8 @@ TempoMap::add_tempo (TempoPoint * tp)
const superclock_t sclock_limit = tp->sclock(); const superclock_t sclock_limit = tp->sclock();
const Beats beats_limit = tp->beats (); const Beats beats_limit = tp->beats ();
switch (time_domain()) { for (t = _tempos.begin(); t != _tempos.end() && t->beats() < beats_limit; ++t);
case AudioTime: for (p = _points.begin(); p != _points.end() && p->beats() < beats_limit; ++p);
for (t = _tempos.begin(); t != _tempos.end() && t->sclock() < sclock_limit; ++t);
for (p = _points.begin(); p != _points.end() && p->sclock() < sclock_limit; ++p);
break;
case BeatTime:
for (t = _tempos.begin(); t != _tempos.end() && t->beats() < beats_limit; ++t);
for (p = _points.begin(); p != _points.end() && p->beats() < beats_limit; ++p);
break;
}
bool replaced = false; bool replaced = false;
TempoPoint* ret = 0; TempoPoint* ret = 0;
@ -1297,26 +1236,14 @@ TempoMap::move_meter (MeterPoint const & mp, timepos_t const & when, bool push)
superclock_t sc; superclock_t sc;
Beats beats; Beats beats;
BBT_Time bbt; BBT_Time bbt;
TimeDomain td (time_domain());
bool round_up; bool round_up;
switch (td) { beats = when.beats ();
case AudioTime:
sc = when.superclocks(); if (beats > mp.beats ()) {
if (sc > mp.sclock()) { round_up = true;
round_up = true; } else {
} else { round_up = false;
round_up = false;
}
break;
case BeatTime:
beats = when.beats ();
if (beats > mp.beats ()) {
round_up = true;
} else {
round_up = false;
}
break;
} }
/* Do not allow moving a meter marker to the same position as /* Do not allow moving a meter marker to the same position as
@ -1326,106 +1253,33 @@ TempoMap::move_meter (MeterPoint const & mp, timepos_t const & when, bool push)
Tempos::iterator t, prev_t; Tempos::iterator t, prev_t;
Meters::iterator m, prev_m; Meters::iterator m, prev_m;
switch (time_domain()) { /* meter changes must be on bar */
case AudioTime: { for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->beats() < beats; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->beats() < beats && *m != mp; ++m) { prev_m = m; }
/* Find TempoMetric *prior* to the intended new location, * using superclock position */ assert (prev_m != _meters.end());
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); }
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->sclock() < sc; ++t) { prev_t = t; } TempoMetric metric (*prev_t, *prev_m);
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->sclock() < sc && *m != mp; ++m) { prev_m = m; } bbt = metric.bbt_at (beats);
assert (prev_m != _meters.end()); if (round_up) {
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); } bbt = metric.meter().round_up_to_bar (bbt);
TempoMetric metric (*prev_t, *prev_m); } else {
bbt = metric.meter().round_down_to_bar (bbt);
/* check the duration of 1 bar here. If we're not more than }
* half-way to the next bar (in whatever the appropriate for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->bbt() < bbt; ++t) { prev_t = t; }
* direction is), don't move for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->bbt() < bbt && *m != mp; ++m) { prev_m = m; }
*/ assert (prev_m != _meters.end());
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); }
const superclock_t one_bar = metric.superclocks_per_bar (); metric = TempoMetric (*prev_t, *prev_m);
if (abs (sc - mp.sclock()) < one_bar / 2) { beats = metric.quarters_at (bbt);
return false; for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end(); ++m) {
} if (&*m != &mp) {
if (m->beats() == beats) {
/* compute the BBT at the given superclock position, given the prior TempoMetric */ return false;
bbt = metric.bbt_at (timepos_t::from_superclock (sc));
/* meter changes must fall on a bar change */
if (round_up) {
bbt = metric.meter().round_up_to_bar (bbt);
} else {
bbt = metric.meter().round_down_to_bar (bbt);
}
/* Repeat using the computed (new) BBT location */
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->bbt() < bbt && *m != mp; ++m) {prev_m = m; }
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->bbt() < bbt; ++t) { prev_t = t; }
if (prev_m == _meters.end()) {
/* given position is going to put us over the initial
meter. Not allowed for a meter move.
*/
return false;
}
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); }
metric = TempoMetric (*prev_t, *prev_m);
/* recompute the superclock position of the new BBT position,
* since this is what we'll use to set the meter point.
*/
sc = metric.superclock_at (bbt);
/* check to see if there's already a meter point at that location */
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end(); ++m) {
if (&*m != &mp) {
if (m->sclock() == sc) {
return false;
}
} }
} }
beats = metric.quarters_at (bbt);
break;
} }
case BeatTime: { sc = metric.superclock_at (bbt);
/* meter changes must be on bar */
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->beats() < beats; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->beats() < beats && *m != mp; ++m) { prev_m = m; }
assert (prev_m != _meters.end());
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); }
TempoMetric metric (*prev_t, *prev_m);
bbt = metric.bbt_at (beats);
if (round_up) {
bbt = metric.meter().round_up_to_bar (bbt);
} else {
bbt = metric.meter().round_down_to_bar (bbt);
}
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->bbt() < bbt; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->bbt() < bbt && *m != mp; ++m) { prev_m = m; }
assert (prev_m != _meters.end());
if (prev_t == _tempos.end()) { prev_t = _tempos.begin(); }
metric = TempoMetric (*prev_t, *prev_m);
beats = metric.quarters_at (bbt);
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end(); ++m) {
if (&*m != &mp) {
if (m->beats() == beats) {
return false;
}
}
}
sc = metric.superclock_at (bbt);
break;
}
default:
/* NOTREACHED */
return false;
}
if (mp.sclock() == sc && mp.beats() == beats && mp.bbt() == bbt) { if (mp.sclock() == sc && mp.beats() == beats && mp.bbt() == bbt) {
return false; return false;
@ -1472,16 +1326,8 @@ TempoMap::move_tempo (TempoPoint const & tp, timepos_t const & when, bool push)
superclock_t sc; superclock_t sc;
Beats beats; Beats beats;
BBT_Time bbt; BBT_Time bbt;
TimeDomain td (time_domain());
switch (td) { beats = when.beats ();
case AudioTime:
sc = when.superclocks();
break;
case BeatTime:
beats = when.beats ();
break;
}
/* Do not allow moving a tempo marker to the same position as /* Do not allow moving a tempo marker to the same position as
* an existing one. * an existing one.
@ -1490,45 +1336,15 @@ TempoMap::move_tempo (TempoPoint const & tp, timepos_t const & when, bool push)
Tempos::iterator t, prev_t; Tempos::iterator t, prev_t;
Meters::iterator m, prev_m; Meters::iterator m, prev_m;
switch (time_domain()) { /* tempo changes must be on beat */
case AudioTime: { beats = beats.round_to_beat ();
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->sclock() < sc && *t != tp; ++t) { prev_t = t; } for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->beats() < beats && *t != tp; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->sclock() < sc; ++m) { prev_m = m; } for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->beats() < beats; ++m) { prev_m = m; }
assert (prev_t != _tempos.end()); assert (prev_t != _tempos.end());
if (prev_m == _meters.end()) { prev_m = _meters.begin(); } assert (prev_m != _meters.end());
TempoMetric metric (*prev_t, *prev_m); TempoMetric metric (*prev_t, *prev_m);
beats = metric.quarters_at_superclock (sc); sc = metric.superclock_at (beats);
/* tempo changes must be on beat, so round and then bbt = metric.bbt_at (beats);
* recompute superclock and BBT with rounded result
*/
beats = beats.round_to_beat ();
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->sclock() < sc && *t != tp; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->sclock() < sc; ++m) { prev_m = m; }
assert (prev_t != _tempos.end());
if (prev_m == _meters.end()) { prev_m = _meters.begin(); }
metric = TempoMetric (*prev_t, *prev_m);
sc = metric.superclock_at (beats);
bbt = metric.bbt_at (beats);
break;
}
case BeatTime: {
/* tempo changes must be on beat */
beats = beats.round_to_beat ();
for (t = _tempos.begin(), prev_t = _tempos.end(); t != _tempos.end() && t->beats() < beats && *t != tp; ++t) { prev_t = t; }
for (m = _meters.begin(), prev_m = _meters.end(); m != _meters.end() && m->beats() < beats; ++m) { prev_m = m; }
assert (prev_t != _tempos.end());
assert (prev_m != _meters.end());
TempoMetric metric (*prev_t, *prev_m);
sc = metric.superclock_at (beats);
bbt = metric.bbt_at (beats);
break;
}
default:
/* NOTREACHED */
return false;
}
if (tp.sclock() == sc && tp.beats() == beats && tp.bbt() == bbt) { if (tp.sclock() == sc && tp.beats() == beats && tp.bbt() == bbt) {
return false; return false;
@ -2473,7 +2289,6 @@ TempoMap::get_state () const
{ {
XMLNode* node = new XMLNode (X_("TempoMap")); XMLNode* node = new XMLNode (X_("TempoMap"));
node->set_property (X_("time-domain"), _time_domain);
node->set_property (X_("superclocks-per-second"), superclock_ticks_per_second()); node->set_property (X_("superclocks-per-second"), superclock_ticks_per_second());
XMLNode* children; XMLNode* children;
@ -2514,8 +2329,6 @@ TempoMap::set_state (XMLNode const & node, int version)
set_superclock_ticks_per_second (sc); set_superclock_ticks_per_second (sc);
} }
node.get_property (X_("time-domain"), _time_domain);
XMLNodeList const & children (node.children()); XMLNodeList const & children (node.children());
for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) { for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {

View File

@ -86,7 +86,7 @@ class /*LIBTEMPORAL_API*/ Point : public point_hook {
LIBTEMPORAL_API BBT_Time const & bbt() const { return _bbt; } LIBTEMPORAL_API BBT_Time const & bbt() const { return _bbt; }
LIBTEMPORAL_API samplepos_t sample(samplecnt_t sr) const { return superclock_to_samples (sclock(), sr); } LIBTEMPORAL_API samplepos_t sample(samplecnt_t sr) const { return superclock_to_samples (sclock(), sr); }
LIBTEMPORAL_API timepos_t time() const; LIBTEMPORAL_API virtual timepos_t time() const = 0;
struct LIBTEMPORAL_API sclock_comparator { struct LIBTEMPORAL_API sclock_comparator {
bool operator() (Point const & a, Point const & b) const { bool operator() (Point const & a, Point const & b) const {
@ -360,6 +360,8 @@ class /*LIBTEMPORAL_API*/ MeterPoint : public Meter, public meter_hook, public v
} }
LIBTEMPORAL_API XMLNode& get_state () const; LIBTEMPORAL_API XMLNode& get_state () const;
LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
}; };
/* A TempoPoint is a combination of a Tempo with a Point. However, if the temp /* A TempoPoint is a combination of a Tempo with a Point. However, if the temp
@ -420,6 +422,8 @@ class /*LIBTEMPORAL_API*/ TempoPoint : public Tempo, public tempo_hook, public v
LIBTEMPORAL_API Beats quarters_at_sample (samplepos_t sc) const { return quarters_at_superclock (samples_to_superclock (sc, TEMPORAL_SAMPLE_RATE)); } LIBTEMPORAL_API Beats quarters_at_sample (samplepos_t sc) const { return quarters_at_superclock (samples_to_superclock (sc, TEMPORAL_SAMPLE_RATE)); }
LIBTEMPORAL_API Beats quarters_at_superclock (superclock_t sc) const; LIBTEMPORAL_API Beats quarters_at_superclock (superclock_t sc) const;
LIBTEMPORAL_API timepos_t time() const { return timepos_t (beats()); }
private: private:
double _omega; double _omega;
@ -529,6 +533,8 @@ class /*LIBTEMPORAL_API*/ MusicTimePoint : public bartime_hook, public virtual
return TempoPoint::operator== (other) && MeterPoint::operator== (other); return TempoPoint::operator== (other) && MeterPoint::operator== (other);
} }
LIBTEMPORAL_API timepos_t time() const { return timepos_t::from_superclock (TempoPoint::sclock()); }
LIBTEMPORAL_API XMLNode & get_state () const; LIBTEMPORAL_API XMLNode & get_state () const;
}; };
@ -598,6 +604,8 @@ class LIBTEMPORAL_API TempoMapPoint : public Point, public TempoMetric
bool is_explicit_position() const { return false; } bool is_explicit_position() const { return false; }
bool is_explicit () const { return is_explicit_meter() || is_explicit_tempo() || is_explicit_position(); } bool is_explicit () const { return is_explicit_meter() || is_explicit_tempo() || is_explicit_position(); }
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()); } }
private: private:
bool _floating; bool _floating;
}; };
@ -714,7 +722,6 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
LIBTEMPORAL_API bool move_tempo (TempoPoint const & point, timepos_t const & destination, bool push = false); LIBTEMPORAL_API bool move_tempo (TempoPoint const & point, timepos_t const & destination, bool push = false);
LIBTEMPORAL_API bool move_meter (MeterPoint const & point, timepos_t const & destination, bool push = false); LIBTEMPORAL_API bool move_meter (MeterPoint const & point, timepos_t const & destination, bool push = false);
LIBTEMPORAL_API void set_time_domain (TimeDomain td);
LIBTEMPORAL_API int set_state (XMLNode const&, int version); LIBTEMPORAL_API int set_state (XMLNode const&, int version);
LIBTEMPORAL_API void twist_tempi (TempoPoint* ts, samplepos_t start_sample, samplepos_t end_sample); LIBTEMPORAL_API void twist_tempi (TempoPoint* ts, samplepos_t start_sample, samplepos_t end_sample);
@ -723,8 +730,6 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
/* END OF MODIFYING METHODS */ /* END OF MODIFYING METHODS */
LIBTEMPORAL_API TimeDomain time_domain() const { return _time_domain; }
/* rather than giving direct access to the intrusive list members, /* rather than giving direct access to the intrusive list members,
* offer one that uses an STL container instead. * offer one that uses an STL container instead.
*/ */
@ -880,8 +885,6 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
MusicTimes _bartimes; MusicTimes _bartimes;
Points _points; Points _points;
TimeDomain _time_domain;
int set_tempos_from_state (XMLNode const &); int set_tempos_from_state (XMLNode const &);
int set_meters_from_state (XMLNode const &); int set_meters_from_state (XMLNode const &);
int set_music_times_from_state (XMLNode const &); int set_music_times_from_state (XMLNode const &);