From 2858b0474e4bedf3ab67a539a7f0d12380ac7bda Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 4 Jan 2012 17:55:42 +0000 Subject: fix (?) tricky locking issues in the tempo map by adding a second lock and independently locking the metrics and the map itself git-svn-id: svn://localhost/ardour2/branches/3.0@11157 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/tempo.h | 33 +++---- libs/ardour/tempo.cc | 242 ++++++++++++++++++++++++++------------------- 2 files changed, 156 insertions(+), 119 deletions(-) diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 3f4b783de7..f0a63be05f 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -223,16 +223,14 @@ class TempoMap : public PBD::StatefulDestructible typedef std::vector BBTPointList; template void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) { - Glib::RWLock::ReaderLock lm (lock); + Glib::RWLock::ReaderLock lm (metrics_lock); (obj.*method)(*metrics); } - const BBTPointList& map() const { return _map ; } - void map (BBTPointList::const_iterator&, BBTPointList::const_iterator&, framepos_t start, framepos_t end); - void bbt_time (framepos_t when, Timecode::BBT_Time&); + void bbt_time (framepos_t when, Timecode::BBT_Time&); framecnt_t frame_time (const Timecode::BBT_Time&); framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir); @@ -299,31 +297,32 @@ class TempoMap : public PBD::StatefulDestructible framepos_t last_bbt_when; bool last_bbt_valid; Timecode::BBT_Time last_bbt; - mutable Glib::RWLock lock; - BBTPointList _map; + mutable Glib::RWLock metrics_lock; + mutable Glib::RWLock map_lock; + BBTPointList* _map; void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1); void require_map_to (framepos_t pos); void require_map_to (const Timecode::BBT_Time&); - BBTPointList::const_iterator bbt_before_or_at (framepos_t); - BBTPointList::const_iterator bbt_after_or_at (framepos_t); - BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&); - + BBTPointList::const_iterator bbt_before_or_at (framepos_t); + BBTPointList::const_iterator bbt_after_or_at (framepos_t); + BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&); + void timestamp_metrics_from_audio_time (); - + framepos_t round_to_type (framepos_t fr, int dir, BBTPointType); - + void bbt_time_unlocked (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&); - - framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir); - + + framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir); + const MeterSection& first_meter() const; const TempoSection& first_tempo() const; - + int move_metric_section (MetricSection&, const Timecode::BBT_Time& to); void do_insert (MetricSection* section); - + Timecode::BBT_Time bbt_add (const Timecode::BBT_Time&, const Timecode::BBT_Time&, const TempoMetric&) const; Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const; Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const; diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 54bb23d517..e8f894c1b4 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -278,6 +278,7 @@ struct MetricSectionSorter { TempoMap::TempoMap (framecnt_t fr) { metrics = new Metrics; + _map = new BBTPointList; _frame_rate = fr; last_bbt_valid = false; BBT_Time start; @@ -300,6 +301,8 @@ TempoMap::TempoMap (framecnt_t fr) TempoMap::~TempoMap () { + delete metrics; + delete _map; } void @@ -308,7 +311,7 @@ TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation) 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) { @@ -322,13 +325,10 @@ TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation) } } } - - if (removed && complete_operation) { - recompute_map (false); - } } if (removed && complete_operation) { + recompute_map (false); PropertyChanged (PropertyChange ()); } } @@ -339,7 +339,7 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation) 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) { @@ -353,15 +353,10 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation) } } } - - if (removed && complete_operation) { - recompute_map (true); - } - - } if (removed && complete_operation) { + recompute_map (true); PropertyChanged (PropertyChange ()); } } @@ -369,9 +364,6 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation) 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); @@ -386,8 +378,6 @@ TempoMap::do_insert (MetricSection* section) sections based on this new meter. */ - reassign_tempo_bbt = true; - if ((section->start().beats != 1) || (section->start().ticks != 0)) { BBT_Time corrected = section->start(); @@ -469,8 +459,6 @@ TempoMap::do_insert (MetricSection* section) metrics->insert (metrics->end(), section); } } - - recompute_map (reassign_tempo_bbt); } void @@ -482,9 +470,12 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T 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); } @@ -495,7 +486,7 @@ void 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; @@ -531,10 +522,12 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where) ts->update_bar_offset_from_bbt (*meter); /* and insert it */ - + do_insert (ts); } + recompute_map (false); + PropertyChanged (PropertyChange ()); } @@ -547,9 +540,11 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T 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); } @@ -560,7 +555,7 @@ void 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 @@ -576,10 +571,12 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where) /* 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); @@ -598,10 +595,10 @@ TempoMap::change_initial_tempo (double beats_per_minute, double note_type) for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) { if ((t = dynamic_cast (*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; } @@ -648,12 +645,12 @@ TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, d /* 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 ()); } @@ -774,7 +771,14 @@ TempoMap::timestamp_metrics_from_audio_time () 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); } } @@ -782,7 +786,14 @@ TempoMap::require_map_to (framepos_t 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); } } @@ -799,20 +810,24 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end) 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 (*i)) != 0) { meter = ms; @@ -873,7 +888,7 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end) ++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) { @@ -973,18 +988,24 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t 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; @@ -1021,7 +1042,7 @@ TempoMap::metric_at (framepos_t frame) const 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; @@ -1058,7 +1079,7 @@ void 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); } @@ -1081,7 +1102,7 @@ TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt, const BBTPointList 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)); @@ -1097,7 +1118,7 @@ TempoMap::frame_time (const BBT_Time& bbt) 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; @@ -1119,7 +1140,7 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i 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 */ @@ -1130,19 +1151,19 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i 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 */ @@ -1156,25 +1177,19 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i 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; @@ -1204,9 +1219,9 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir) } 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; } @@ -1229,7 +1244,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir) } 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; } @@ -1255,9 +1270,9 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir) 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)); } @@ -1267,7 +1282,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir) /* 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; } @@ -1291,6 +1306,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir) 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) { @@ -1299,7 +1315,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type) 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)); @@ -1313,7 +1329,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type) } while (!(*fi).is_bar()) { - if (fi == _map.begin()) { + if (fi == _map->begin()) { break; } fi--; @@ -1332,7 +1348,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type) while (!(*fi).is_bar()) { fi++; - if (fi == _map.end()) { + if (fi == _map->end()) { --fi; break; } @@ -1354,7 +1370,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type) } while ((*prev).beat != 1) { - if (prev == _map.begin()) { + if (prev == _map->begin()) { break; } prev--; @@ -1362,7 +1378,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type) while ((*next).beat != 1) { next++; - if (next == _map.end()) { + if (next == _map->end()) { --next; break; } @@ -1425,18 +1441,15 @@ TempoMap::map (TempoMap::BBTPointList::const_iterator& begin, 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; @@ -1482,7 +1495,7 @@ TempoMap::get_state () 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()); } @@ -1495,7 +1508,7 @@ int TempoMap::set_state (const XMLNode& node, int /*version*/) { { - Glib::RWLock::WriterLock lm (lock); + Glib::RWLock::WriterLock lm (metrics_lock); XMLNodeList nlist; XMLNodeConstIterator niter; @@ -1545,13 +1558,12 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) } if (niter == nlist.end()) { - MetricSectionSorter cmp; metrics->sort (cmp); - recompute_map (true); } } + recompute_map (true); PropertyChanged (PropertyChange ()); return 0; @@ -1560,6 +1572,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) void TempoMap::dump (std::ostream& o) const { + Glib::RWLock::ReaderLock lm (metrics_lock); const MeterSection* m; const TempoSection* t; @@ -1578,7 +1591,7 @@ TempoMap::dump (std::ostream& o) const 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) { @@ -1593,7 +1606,7 @@ TempoMap::n_tempos() const 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) { @@ -1608,6 +1621,7 @@ TempoMap::n_meters() const 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); @@ -1638,6 +1652,7 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) 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; @@ -1650,7 +1665,7 @@ TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op) /* 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) { @@ -1683,6 +1698,7 @@ TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op) 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; @@ -1697,7 +1713,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) /* 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) { @@ -1710,7 +1726,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) } } - if (i != _map.end()) { + if (i != _map->end()) { break; } @@ -1722,7 +1738,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) /* 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; } @@ -1741,6 +1757,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) 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; @@ -1755,11 +1772,11 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t 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. @@ -1775,12 +1792,17 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t 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; } @@ -1788,9 +1810,14 @@ TempoMap::bbt_before_or_at (framepos_t pos) 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; } @@ -1803,17 +1830,28 @@ struct bbtcmp { 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; } -- cgit v1.2.3