TempoMap::TempoMap (framecnt_t fr)
{
metrics = new Metrics;
+ _map = new BBTPointList;
_frame_rate = fr;
last_bbt_valid = false;
BBT_Time start;
TempoMap::~TempoMap ()
{
+ delete metrics;
+ delete _map;
}
void
bool removed = false;
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
}
}
}
-
- if (removed && complete_operation) {
- recompute_map (false);
- }
}
if (removed && complete_operation) {
+ recompute_map (false);
PropertyChanged (PropertyChange ());
}
}
bool removed = false;
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
Metrics::iterator i;
for (i = metrics->begin(); i != metrics->end(); ++i) {
}
}
}
-
- if (removed && complete_operation) {
- recompute_map (true);
- }
-
-
}
if (removed && complete_operation) {
+ recompute_map (true);
PropertyChanged (PropertyChange ());
}
}
void
TempoMap::do_insert (MetricSection* section)
{
- /* CALLER MUST HOLD WRITE LOCK */
-
- bool reassign_tempo_bbt = false;
bool need_add = true;
assert (section->start().ticks == 0);
sections based on this new meter.
*/
- reassign_tempo_bbt = true;
-
if ((section->start().beats != 1) || (section->start().ticks != 0)) {
BBT_Time corrected = section->start();
metrics->insert (metrics->end(), section);
}
}
-
- recompute_map (reassign_tempo_bbt);
}
void
remove_tempo (ts, false);
add_tempo (tempo, where);
} else {
- Glib::RWLock::WriterLock lm (lock);
- /* cannot move the first tempo section */
- *((Tempo*)&first) = tempo;
+ {
+ Glib::RWLock::WriterLock lm (metrics_lock);
+ /* cannot move the first tempo section */
+ *((Tempo*)&first) = tempo;
+ }
+
recompute_map (false);
}
TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
/* new tempos always start on a beat */
where.ticks = 0;
ts->update_bar_offset_from_bbt (*meter);
/* and insert it */
-
+
do_insert (ts);
}
+ recompute_map (false);
+
PropertyChanged (PropertyChange ());
}
remove_meter (ms, false);
add_meter (meter, where);
} else {
- Glib::RWLock::WriterLock lm (lock);
- /* cannot move the first meter section */
- *((Meter*)&first) = meter;
+ {
+ Glib::RWLock::WriterLock lm (metrics_lock);
+ /* cannot move the first meter section */
+ *((Meter*)&first) = meter;
+ }
recompute_map (true);
}
TempoMap::add_meter (const Meter& meter, BBT_Time where)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
/* a new meter always starts a new bar on the first beat. so
round the start time appropriately. remember that
/* new meters *always* start on a beat. */
where.ticks = 0;
-
+
do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
}
+ recompute_map (true);
+
#ifndef NDEBUG
if (DEBUG_ENABLED(DEBUG::TempoMap)) {
dump (std::cerr);
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
*((Tempo*) t) = newtempo;
- recompute_map (false);
}
+ recompute_map (false);
PropertyChanged (PropertyChange ());
break;
}
/* reset */
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
/* cannot move the first tempo section */
*((Tempo*)prev) = newtempo;
- recompute_map (false);
}
+ recompute_map (false);
PropertyChanged (PropertyChange ());
}
void
TempoMap::require_map_to (framepos_t pos)
{
- if (_map.empty() || _map.back().frame < pos) {
+ bool revise_map;
+
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ revise_map = (_map->empty() || _map->back().frame < pos);
+ }
+
+ if (revise_map) {
recompute_map (false, pos);
}
}
void
TempoMap::require_map_to (const BBT_Time& bbt)
{
- if (_map.empty() || _map.back().bbt() < bbt) {
+ bool revise_map;
+
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ revise_map = (_map->empty() || _map->back().bbt() < bbt);
+ }
+
+ if (revise_map) {
recompute_map (false, 99);
}
}
double current_frame;
BBT_Time current;
Metrics::iterator next_metric;
+ BBTPointList* new_map = new BBTPointList;
if (end < 0) {
- if (_map.empty()) {
+
+ Glib::RWLock::ReaderLock lm (map_lock);
+
+ if (_map->empty()) {
/* compute 1 mins worth */
end = _frame_rate * 60;
} else {
- end = _map.back().frame;
+ end = _map->back().frame;
}
}
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
-
- _map.clear ();
+ Glib::RWLock::ReaderLock lm (metrics_lock);
+
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
meter = ms;
++next_metric; // skip tempo (or meter)
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
- _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
+ new_map->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
while (current_frame < end) {
if (current.beats == 1) {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
- _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
+ new_map->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
} else {
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
- _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
+ new_map->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
}
}
+
+ {
+ Glib::RWLock::WriterLock lm (map_lock);
+ swap (_map, new_map);
+ delete new_map;
+ }
}
TempoMetric
TempoMap::metric_at (framepos_t frame) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
TempoMetric m (first_meter(), first_tempo());
const Meter* meter;
const Tempo* tempo;
TempoMetric
TempoMap::metric_at (BBT_Time bbt) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
TempoMetric m (first_meter(), first_tempo());
const Meter* meter;
const Tempo* tempo;
TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
{
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator i = bbt_before_or_at (frame);
bbt_time_unlocked (frame, bbt, i);
}
framepos_t
TempoMap::frame_time (const BBT_Time& bbt)
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator s = bbt_point_for (BBT_Time (1, 1, 0));
BBTPointList::const_iterator e = bbt_point_for (BBT_Time (bbt.bars, bbt.beats, 0));
framecnt_t
TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (map_lock);
framecnt_t frames = 0;
BBT_Time when;
BBTPointList::const_iterator start (wi);
double tick_frames = 0;
- assert (wi != _map.end());
+ assert (wi != _map->end());
/* compute how much rounding we did because of non-zero ticks */
uint32_t bars = 0;
uint32_t beats = 0;
- while (wi != _map.end() && bars < bbt.bars) {
+ while (wi != _map->end() && bars < bbt.bars) {
++wi;
if ((*wi).is_bar()) {
++bars;
}
}
- assert (wi != _map.end());
+ assert (wi != _map->end());
- while (wi != _map.end() && beats < bbt.beats) {
+ while (wi != _map->end() && beats < bbt.beats) {
++wi;
++beats;
}
- assert (wi != _map.end());
+ assert (wi != _map->end());
/* add any additional frames related to ticks in the added value */
framepos_t
TempoMap::round_to_bar (framepos_t fr, int dir)
{
- {
- Glib::RWLock::ReaderLock lm (lock);
- return round_to_type (fr, dir, Bar);
- }
+ return round_to_type (fr, dir, Bar);
}
framepos_t
TempoMap::round_to_beat (framepos_t fr, int dir)
{
- {
- Glib::RWLock::ReaderLock lm (lock);
- return round_to_type (fr, dir, Beat);
- }
+ return round_to_type (fr, dir, Beat);
}
framepos_t
TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator i = bbt_before_or_at (fr);
BBT_Time the_beat;
uint32_t ticks_one_subdivisions_worth;
}
if (the_beat.ticks > BBT_Time::ticks_per_bar_division) {
- assert (i != _map.end());
+ assert (i != _map->end());
++i;
- assert (i != _map.end());
+ assert (i != _map->end());
the_beat.ticks -= BBT_Time::ticks_per_bar_division;
}
}
if (the_beat.ticks < difference) {
- if (i == _map.begin()) {
+ if (i == _map->begin()) {
/* can't go backwards from wherever pos is, so just return it */
return fr;
}
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", the_beat.ticks));
if (the_beat.ticks > BBT_Time::ticks_per_bar_division) {
- assert (i != _map.end());
+ assert (i != _map->end());
++i;
- assert (i != _map.end());
+ assert (i != _map->end());
the_beat.ticks -= BBT_Time::ticks_per_bar_division;
DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", the_beat));
}
/* closer to previous subdivision, so shift backward */
if (rem > the_beat.ticks) {
- if (i == _map.begin()) {
+ if (i == _map->begin()) {
/* can't go backwards past zero, so ... */
return 0;
}
framepos_t
TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
{
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator fi;
if (dir > 0) {
fi = bbt_before_or_at (frame);
}
- assert (fi != _map.end());
+ assert (fi != _map->end());
DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3|%4 @ %5) to bars in direction %2\n", frame, dir, (*fi).bar, (*fi).beat, (*fi).frame));
}
while (!(*fi).is_bar()) {
- if (fi == _map.begin()) {
+ if (fi == _map->begin()) {
break;
}
fi--;
while (!(*fi).is_bar()) {
fi++;
- if (fi == _map.end()) {
+ if (fi == _map->end()) {
--fi;
break;
}
}
while ((*prev).beat != 1) {
- if (prev == _map.begin()) {
+ if (prev == _map->begin()) {
break;
}
prev--;
while ((*next).beat != 1) {
next++;
- if (next == _map.end()) {
+ if (next == _map->end()) {
--next;
break;
}
TempoMap::BBTPointList::const_iterator& end,
framepos_t lower, framepos_t upper)
{
- if (_map.empty() || upper >= _map.back().frame) {
- recompute_map (false, upper);
- }
-
- begin = lower_bound (_map.begin(), _map.end(), lower);
- end = upper_bound (_map.begin(), _map.end(), upper);
+ require_map_to (upper);
+ begin = lower_bound (_map->begin(), _map->end(), lower);
+ end = upper_bound (_map->begin(), _map->end(), upper);
}
const TempoSection&
TempoMap::tempo_section_at (framepos_t frame) const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
Metrics::const_iterator i;
TempoSection* prev = 0;
XMLNode *root = new XMLNode ("TempoMap");
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
for (i = metrics->begin(); i != metrics->end(); ++i) {
root->add_child_nocopy ((*i)->get_state());
}
TempoMap::set_state (const XMLNode& node, int /*version*/)
{
{
- Glib::RWLock::WriterLock lm (lock);
+ Glib::RWLock::WriterLock lm (metrics_lock);
XMLNodeList nlist;
XMLNodeConstIterator niter;
}
if (niter == nlist.end()) {
-
MetricSectionSorter cmp;
metrics->sort (cmp);
- recompute_map (true);
}
}
+ recompute_map (true);
PropertyChanged (PropertyChange ());
return 0;
void
TempoMap::dump (std::ostream& o) const
{
+ Glib::RWLock::ReaderLock lm (metrics_lock);
const MeterSection* m;
const TempoSection* t;
int
TempoMap::n_tempos() const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
int
TempoMap::n_meters() const
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (metrics_lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
void
TempoMap::insert_time (framepos_t where, framecnt_t amount)
{
+ Glib::RWLock::WriterLock lm (metrics_lock);
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
if ((*i)->frame() >= where && (*i)->movable ()) {
(*i)->set_frame ((*i)->frame() + amount);
framepos_t
TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op)
{
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator i;
framecnt_t extra_frames = 0;
/* walk backwards */
- while (i != _map.begin() && (op.bars || op.beats)) {
+ while (i != _map->begin() && (op.bars || op.beats)) {
--i;
if ((*i).is_bar()) {
if (op.bars) {
framepos_t
TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
{
+ Glib::RWLock::ReaderLock lm (map_lock);
BBT_Time op_copy (op);
int additional_minutes = 1;
BBTPointList::const_iterator i;
/* we know that (*i).frame is before or equal to pos */
backup_frames = pos - (*i).frame;
- while (i != _map.end() && (op.bars || op.beats)) {
+ while (i != _map->end() && (op.bars || op.beats)) {
++i;
if ((*i).is_bar()) {
if (op.bars) {
}
}
- if (i != _map.end()) {
+ if (i != _map->end()) {
break;
}
/* go back and try again */
warning << "reached end of map with op now at " << op << " end = "
- << _map.back().frame << ' ' << _map.back().bar << '|' << _map.back().beat << ", trying to walk "
+ << _map->back().frame << ' ' << _map->back().bar << '|' << _map->back().beat << ", trying to walk "
<< op_copy << " ... retry"
<< endmsg;
}
Evoral::MusicalTime
TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance)
{
+ Glib::RWLock::ReaderLock lm (map_lock);
BBTPointList::const_iterator i = bbt_after_or_at (pos);
Evoral::MusicalTime beats = 0;
framepos_t end = pos + distance;
beats += ((*i).frame - pos) / (*i).meter->frames_per_division (*(*i).tempo, _frame_rate);
}
- while (i != _map.end() && (*i).frame < end) {
+ while (i != _map->end() && (*i).frame < end) {
++i;
beats++;
}
- assert (i != _map.end());
+ assert (i != _map->end());
/* if our ending BBTPoint is after the end, subtract a fractional beat
to represent that distance.
TempoMap::BBTPointList::const_iterator
TempoMap::bbt_before_or_at (framepos_t pos)
{
+ BBTPointList::const_iterator i;
+
require_map_to (pos);
- BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), pos);
- assert (i != _map.end());
- if ((*i).frame > pos) {
- assert (i != _map.begin());
- --i;
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ i = lower_bound (_map->begin(), _map->end(), pos);
+ assert (i != _map->end());
+ if ((*i).frame > pos) {
+ assert (i != _map->begin());
+ --i;
+ }
}
return i;
}
TempoMap::BBTPointList::const_iterator
TempoMap::bbt_after_or_at (framepos_t pos)
{
+ BBTPointList::const_iterator i;
+
require_map_to (pos);
- BBTPointList::const_iterator i = upper_bound (_map.begin(), _map.end(), pos);
- assert (i != _map.end());
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ i = upper_bound (_map->begin(), _map->end(), pos);
+ assert (i != _map->end());
+ }
return i;
}
TempoMap::BBTPointList::const_iterator
TempoMap::bbt_point_for (const BBT_Time& bbt)
{
+ BBTPointList::const_iterator i;
bbtcmp cmp;
int additional_minutes = 1;
- while (_map.empty() || _map.back().bar < (bbt.bars + 1)) {
+ while (1) {
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ if (!_map->empty() && _map->back().bar >= (bbt.bars + 1)) {
+ break;
+ }
+ }
/* add some more distance, using bigger steps each time */
- require_map_to (_map.back().frame + (_frame_rate * 60 * additional_minutes));
+ require_map_to (_map->back().frame + (_frame_rate * 60 * additional_minutes));
additional_minutes *= 2;
}
- BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), bbt, cmp);
- assert (i != _map.end());
+ {
+ Glib::RWLock::ReaderLock lm (map_lock);
+ i = lower_bound (_map->begin(), _map->end(), bbt, cmp);
+ assert (i != _map->end());
+ }
+
return i;
}