+/** places a copy of _metrics into copy and returns a pointer
+ * to section's equivalent.
+ */
+TempoSection*
+TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
+{
+ TempoSection* t;
+ TempoSection* ret = 0;
+ MeterSection* m;
+
+ for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (t == section) {
+ if (t->position_lock_style() == MusicTime) {
+ ret = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
+ } else {
+ ret = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
+ }
+ ret->set_active (t->active());
+ ret->set_movable (t->movable());
+ copy.push_back (ret);
+ continue;
+ }
+ TempoSection* cp = 0;
+ if (t->position_lock_style() == MusicTime) {
+ cp = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
+ } else {
+ cp = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
+ }
+ cp->set_active (t->active());
+ cp->set_movable (t->movable());
+ copy.push_back (cp);
+ }
+ if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
+ MeterSection* cp = 0;
+ if (m->position_lock_style() == MusicTime) {
+ cp = new MeterSection (m->pulse(), m->beat(), m->bbt(), m->divisions_per_bar(), m->note_divisor());
+ cp->set_frame (m->frame());
+ } else {
+ cp = new MeterSection (m->frame(), m->beat(), m->bbt(), m->divisions_per_bar(), m->note_divisor());
+ cp->set_pulse (m->pulse());
+ }
+ cp->set_movable (m->movable());
+ copy.push_back (cp);
+ }
+ }
+ //recompute_map (copy);
+ return ret;
+}
+
+bool
+TempoMap::can_solve_bbt (TempoSection* ts, const Tempo& bpm, const BBT_Time& bbt)
+{
+ Metrics copy;
+ TempoSection* new_section = 0;
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ new_section = copy_metrics_and_point (copy, ts);
+ }
+
+ double const beat = bbt_to_beats_locked (copy, bbt);
+ bool ret = solve_map (copy, new_section, bpm, pulse_at_beat_locked (copy, beat));
+
+ Metrics::const_iterator d = copy.begin();
+ while (d != copy.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ return ret;
+}
+
+/**
+* This is for a gui that needs to know the frame of a tempo section if it were to be moved to some bbt time,
+* taking any possible reordering as a consequence of this into account.
+* @param section - the section to be altered
+* @param bpm - the new Tempo
+* @param bbt - the bbt where the altered tempo will fall
+* @return returns - the position in frames where the new tempo section will lie.
+*/
+framepos_t
+TempoMap::predict_tempo_frame (TempoSection* section, const Tempo& bpm, const BBT_Time& bbt)
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ Metrics future_map;
+ framepos_t ret = 0;
+ TempoSection* new_section = copy_metrics_and_point (future_map, section);
+
+ double const beat = bbt_to_beats_locked (future_map, bbt);
+ if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
+ ret = new_section->frame();
+ } else {
+ ret = frame_at_beat_locked (_metrics, beat);
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+ return ret;
+}
+
+double
+TempoMap::predict_tempo_pulse (TempoSection* section, const Tempo& bpm, const framepos_t& frame)
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+ Metrics future_map;
+ double ret = 0.0;
+ TempoSection* new_section = copy_metrics_and_point (future_map, section);
+
+ if (solve_map (future_map, new_section, bpm, frame)) {
+ ret = new_section->pulse();
+ } else {
+ ret = pulse_at_frame_locked (_metrics, frame);
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+ return ret;
+}
+
+void
+TempoMap::gui_move_tempo_frame (TempoSection* ts, const Tempo& bpm, const framepos_t& frame)
+{
+ Metrics future_map;
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ TempoSection* new_section = copy_metrics_and_point (future_map, ts);
+ if (solve_map (future_map, new_section, bpm, frame)) {
+ solve_map (_metrics, ts, bpm, frame);
+ }
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ MetricPositionChanged (); // Emit Signal
+}
+
+void
+TempoMap::gui_move_tempo_beat (TempoSection* ts, const Tempo& bpm, const double& beat)
+{
+ Metrics future_map;
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ TempoSection* new_section = copy_metrics_and_point (future_map, ts);
+ if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
+ solve_map (_metrics, ts, bpm, pulse_at_beat_locked (_metrics, beat));
+ }
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ MetricPositionChanged (); // Emit Signal
+}
+
+void
+TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const framepos_t& frame)
+{
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ solve_map (_metrics, ms, mt, frame);
+ }
+
+ MetricPositionChanged (); // Emit Signal
+}
+
+void
+TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const double& beat)
+{
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ solve_map (_metrics, ms, mt, pulse_at_beat_locked (_metrics, beat));
+ }
+
+ MetricPositionChanged (); // Emit Signal
+}
+
+bool
+TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
+{
+ Metrics future_map;
+ bool can_solve = false;
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ TempoSection* new_section = copy_metrics_and_point (future_map, ts);
+ new_section->set_beats_per_minute (bpm.beats_per_minute());
+ recompute_tempos (future_map);
+
+ if (check_solved (future_map, true)) {
+ ts->set_beats_per_minute (bpm.beats_per_minute());
+ recompute_map (_metrics);
+ can_solve = true;
+ }
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+ if (can_solve) {
+ MetricPositionChanged (); // Emit Signal
+ }
+ return can_solve;
+}
+