From 989089a4e997de450f1249bf24755a729f7568db Mon Sep 17 00:00:00 2001 From: nick_m Date: Fri, 4 Mar 2016 07:32:00 +1100 Subject: [PATCH] Tempo ramps - add method to handle beat-based tempo reordering. clean code. --- gtk2_ardour/editor_drag.cc | 3 +- gtk2_ardour/editor_tempodisplay.cc | 2 +- libs/ardour/ardour/tempo.h | 10 +- libs/ardour/tempo.cc | 175 ++++++++++++++--------------- 4 files changed, 90 insertions(+), 100 deletions(-) diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 00ebdeb125..a27de659ae 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3329,10 +3329,9 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) } framepos_t const pf = adjusted_current_frame (event, false); - double const baf = _editor->session()->tempo_map().beat_at_frame (pf); Tempo const tp = _marker->tempo(); _marker->set_position (pf); - _editor->session()->tempo_map().gui_move_tempo (_real_section, tp, pf, baf); + _editor->session()->tempo_map().gui_move_tempo (_real_section, tp, pf); show_verbose_cursor_time (pf); } diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc index 8509407ff6..bd5ff205e9 100644 --- a/gtk2_ardour/editor_tempodisplay.cc +++ b/gtk2_ardour/editor_tempodisplay.cc @@ -378,7 +378,7 @@ Editor::edit_tempo_section (TempoSection* section) if (tempo_dialog.get_lock_style() == MusicTime) { _session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), beat, tempo_dialog.get_tempo_type()); } else { - framepos_t const f = _session->tempo_map().compute_replacement_tempo_section (section, bpm, beat); + framepos_t const f = _session->tempo_map().compute_new_tempo_frame (section, Tempo (bpm, nt), beat); _session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), f, tempo_dialog.get_tempo_type()); } XMLNode &after = _session->tempo_map().get_state(); diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 5dc9525e4d..02886f448a 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -375,14 +375,12 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible void remove_tempo (const TempoSection&, bool send_signal); void remove_meter (const MeterSection&, bool send_signal); - framepos_t compute_replacement_tempo_section (TempoSection* section, const Tempo& bpm, const double& beat); - Metrics get_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame, const double& beat); - Metrics get_new_order (MeterSection* section, const Meter& mt, const framepos_t& frame, const double& beat); + framepos_t compute_new_tempo_frame (TempoSection* section, const Tempo& bpm, const double& beat); void replace_tempo (const TempoSection&, const Tempo&, const double& where, TempoSection::Type type); void replace_tempo (const TempoSection&, const Tempo&, const framepos_t& frame, TempoSection::Type type); - void gui_move_tempo (TempoSection*, const Tempo& bpm, const framepos_t& where, const double& beat); + void gui_move_tempo (TempoSection*, const Tempo& bpm, const framepos_t& where); void gui_move_meter (MeterSection*, const Meter& mt, const framepos_t& where, const double& beat); void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); @@ -434,6 +432,10 @@ private: framecnt_t frame_at_tick_locked (double tick) const; framepos_t frame_time_locked (const Timecode::BBT_Time&); + Metrics get_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame); + Metrics get_new_order (TempoSection* section, const Tempo& bpm, const double& beat); + Metrics get_new_order (MeterSection* section, const Meter& mt, const framepos_t& frame, const double& beat); + friend class ::BBTTest; friend class ::FrameposPlusBeatsTest; friend class ::TempoTest; diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 5463d8539b..61389fe715 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -867,89 +867,6 @@ TempoMap::do_insert (MetricSection* section) } } -/** -* This is for a gui that needs to know the frame of a beat if a tempo section were to be moved or altered. -* It actually alters tha ramps up to the beat parameter, so calling this commits you to replacing the section immediately. -* It will not emit a signal or recompute the map, as you probably want to replace the tempo or do somethig else before that happens. -* @param section - the section you want to alter -* @param bpm - the new tempo -* @param beat - the beat where the altered tempo will fall -* @return returns - the position in frames where the new tempo section will lie -*/ -framepos_t -TempoMap::compute_replacement_tempo_section (TempoSection* section, const Tempo& bpm, const double& beat) -{ - Glib::Threads::RWLock::WriterLock lm (lock); - - TempoSection* prev_ts = 0; - TempoSection* t; - framepos_t ret = 0; - MetricSectionSorter cmp; - - for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { - if ((t = dynamic_cast (*i)) != 0) { - if (prev_ts) { - if (section->beat() == t->beat()) { - continue; - } - if (t->beat() > beat){ - prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate); - section->set_beat (beat); - section->set_frame (prev_ts->frame_at_beat (beat, _frame_rate)); - break; - } - - if (t->position_lock_style() == MusicTime) { - prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate); - t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate)); - } else { - prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate)); - t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate)); - } - } - prev_ts = t; - } - } - /* now we do the whole thing again because audio-locked sections will have caused a re-order */ - prev_ts = 0; - metrics.sort (cmp); - - for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { - if ((t = dynamic_cast (*i)) != 0) { - if (prev_ts) { - if (section->beat() == t->beat()) { - continue; - } - if (t->beat() > beat){ - prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate); - ret = prev_ts->frame_at_beat (beat, _frame_rate); - section->set_frame (ret); - prev_ts = section; - break; - } - if (t->position_lock_style() == MusicTime) { - prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate); - t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate)); - } else { - prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate)); - t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate)); - } - } - prev_ts = t; - } - } - - if (!ret) { - prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate); - section->set_beat (beat); - section->set_frame (prev_ts->frame_at_beat (beat, _frame_rate)); - - ret = prev_ts->frame_at_beat (beat, _frame_rate); - } - - return ret; -} - void TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& where, TempoSection::Type type) { @@ -995,7 +912,7 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const frame } Metrics -TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame, const double& beat) +TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame) { Metrics imaginary (metrics); @@ -1007,25 +924,22 @@ TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos MetricSectionFrameSorter fcmp; imaginary.sort (fcmp); - /* recompute */ + /* recompute tempos */ for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { if ((t = dynamic_cast (*i)) != 0) { if (prev_ts) { if (t == section) { /* we have already set the frame - set the beat */ prev_ts->set_c_func (prev_ts->compute_c_func (bpm.beats_per_minute(), frame, _frame_rate)); - //section->set_beat (prev_ts->beat_at_frame (frame, _frame_rate)); section->set_beat (prev_ts->beat_at_tempo (bpm.beats_per_minute(), frame, _frame_rate)); prev_ts = t; continue; } if (t->position_lock_style() == MusicTime) { prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate); - //t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate)); t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), t->beat(), _frame_rate)); } else { prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate)); - //t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate)); t->set_beat (prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate)); } } @@ -1034,7 +948,6 @@ TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos } MetricSectionSorter cmp; imaginary.sort (cmp); - /* to do - check precision using _at_tempo() methods */ /* prev_ts = 0; std::cerr << "dumping imaginary order ------" << std::endl;; @@ -1044,7 +957,66 @@ TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos std::cerr << t->beats_per_minute() << " | " << t->beat() << " | " << t->frame() << std::endl; std::cerr << prev_ts->beats_per_minute() << " | " << prev_ts->beat() << " | " << prev_ts->frame() << std::endl; - std::cerr << t->beats_per_minute() << " | " << prev_ts->beat_at_tempo (t->beats_per_minute()) << " | " << prev_ts->tempo_at_beat(t->beat()) << " | " << prev_ts->frame_at_tempo(t->beats_per_minute(), _frame_rate) << std::endl; + std::cerr << t->beats_per_minute() << " | " << prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame, _frame_rate) << " | " << prev_ts->tempo_at_beat(t->beat()) << " | " << prev_ts->frame_at_tempo(t->beats_per_minute(), t->beat(), _frame_rate) << std::endl; + std::cerr << " ------" << std::endl;; + + } + prev_ts = t; + } + } + std::cerr << "end dump ------"; +*/ + return imaginary; +} + +Metrics +TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const double& beat) +{ + Metrics imaginary (metrics); + + TempoSection* prev_ts = 0; + TempoSection* t; + + /*set beat and sort */ + section->set_beat (beat); + MetricSectionSorter cmp; + imaginary.sort (cmp); + + /* recompute tempo positions */ + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((t = dynamic_cast (*i)) != 0) { + if (prev_ts) { + if (t == section) { + /* we've already set the beat - set the frame */ + prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate); + section->set_frame (prev_ts->frame_at_tempo (bpm.beats_per_minute(), beat, _frame_rate)); + prev_ts = t; + continue; + } + if (t->position_lock_style() == MusicTime) { + prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate); + t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), t->beat(), _frame_rate)); + } else { + prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate)); + t->set_beat (prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate)); + } + } + prev_ts = t; + } + } + + MetricSectionFrameSorter fcmp; + imaginary.sort (fcmp); +/* + prev_ts = 0; + std::cerr << "dumping imaginary order ------" << std::endl;; + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((t = dynamic_cast (*i)) != 0) { + if (prev_ts) { + + std::cerr << t->beats_per_minute() << " | " << t->beat() << " | " << t->frame() << std::endl; + std::cerr << "prev : " << prev_ts->beats_per_minute() << " | " << prev_ts->beat() << " | " << prev_ts->frame() << std::endl; + std::cerr << "calculated : " << t->beats_per_minute() << " | " << prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate) << " | " << prev_ts->tempo_at_beat(t->beat()) << " | " << prev_ts->frame_at_tempo(t->beats_per_minute(), t->frame(), _frame_rate) << std::endl; std::cerr << " ------" << std::endl;; } @@ -1127,12 +1099,30 @@ TempoMap::get_new_order(MeterSection* section, const Meter& mt, const framepos_t return imaginary; } +/** +* This is for a gui that needs to know the frame of a beat if a tempo section were to be moved or altered. +* It actually reorders and partially recomputes tha ramps, so calling this commits you to replacing the section immediately. +* It will not emit a signal as you probably want to replace the tempo or do somethig else before that happens. +* @param section - the section you want to alter +* @param bpm - the new tempo +* @param beat - the beat where the altered tempo will fall +* @return returns - the position in frames where the new tempo section will lie. +*/ +framepos_t +TempoMap::compute_new_tempo_frame (TempoSection* section, const Tempo& bpm, const double& beat) +{ + Glib::Threads::RWLock::WriterLock lm (lock); + Metrics new_order = get_new_order (section, bpm, beat); + + return section->frame(); +} + void -TempoMap::gui_move_tempo (TempoSection* ts, const Tempo& bpm, const framepos_t& frame, const double& beat_where) +TempoMap::gui_move_tempo (TempoSection* ts, const Tempo& bpm, const framepos_t& frame) { { Glib::Threads::RWLock::WriterLock lm (lock); - Metrics new_order = get_new_order (ts, bpm, frame, beat_where); + Metrics new_order = get_new_order (ts, bpm, frame); metrics.clear(); metrics = new_order; @@ -1157,7 +1147,6 @@ TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Typ add_tempo_locked (tempo, where, true, type); } - PropertyChanged (PropertyChange ()); }