diff options
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 25 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/tempo.h | 16 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 229 |
4 files changed, 195 insertions, 77 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index b8339cc557..00ebdeb125 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3122,6 +3122,8 @@ MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) DEBUG_TRACE (DEBUG::Drags, "New MeterMarkerDrag\n"); _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker")); assert (_marker); + _real_section = &_marker->meter(); + } void @@ -3151,15 +3153,15 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move) // leave or lose the original marker (leave if its a copy; lose if its // not, because we'll remove it from the map). + char name[64]; + snprintf (name, sizeof(name), "%g/%g", _marker->meter().divisions_per_bar(), _marker->meter().note_divisor ()); + MeterSection section (_marker->meter()); if (!section.movable()) { return; } - char name[64]; - snprintf (name, sizeof(name), "%g/%g", _marker->meter().divisions_per_bar(), _marker->meter().note_divisor ()); - _marker = new MeterMarker ( *_editor, *_editor->meter_group, @@ -3172,17 +3174,22 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move) swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME); if (!_copy) { + _editor->begin_reversible_command (_("move meter mark")); TempoMap& map (_editor->session()->tempo_map()); /* get current state */ before_state = &map.get_state(); /* remove the section while we drag it */ - map.remove_meter (section, true); + //map.remove_meter (section, true); } + _marker->hide(); } - framepos_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event, false); + double const baf = _editor->session()->tempo_map().beat_at_frame (pf); _marker->set_position (pf); + _editor->session()->tempo_map().gui_move_meter (_real_section, _marker->meter(), pf, baf); + show_verbose_cursor_time (pf); } @@ -3222,8 +3229,6 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) _editor->commit_reversible_command (); } else { - _editor->begin_reversible_command (_("move meter mark")); - /* we removed it before, so add it back now */ if (_marker->meter().position_lock_style() == AudioTime) { map.add_meter (_marker->meter(), _marker->position()); @@ -3325,9 +3330,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); - - _marker->set_position (adjusted_current_frame (event, false)); - _editor->session()->tempo_map().gui_set_tempo_frame (*_real_section, pf, baf); + Tempo const tp = _marker->tempo(); + _marker->set_position (pf); + _editor->session()->tempo_map().gui_move_tempo (_real_section, tp, pf, baf); show_verbose_cursor_time (pf); } diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index bd2672e23e..26029299ce 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -705,6 +705,8 @@ public: private: MeterMarker* _marker; + ARDOUR::MeterSection* _real_section; + bool _copy; XMLNode* before_state; }; diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 4396cb8f99..060507676d 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -185,6 +185,9 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { double tempo_at_frame (framepos_t frame, framecnt_t frame_rate) const; framepos_t frame_at_tempo (double tempo, framecnt_t frame_rate) const; + double tempo_at_beat (double beat) const; + double beat_at_tempo (double tempo) const; + double tick_at_frame (framepos_t frame, framecnt_t frame_rate) const; framepos_t frame_at_tick (double tick, framecnt_t frame_rate) const; @@ -193,6 +196,7 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { void set_c_func_from_tempo_and_beat (double end_bpm, double end_beat, framecnt_t frame_rate); double compute_c_func (double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; + double get_c_func () const { return _c_func; } void set_c_func (double c_func) { _c_func = c_func; } @@ -213,6 +217,9 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { double tick_tempo_at_time (double time) const; double time_at_tick_tempo (double tick_tempo) const; + double tick_tempo_at_tick (double tick) const; + double tick_at_tick_tempo (double tick_tempo) const; + double tick_at_time (double time) const; double time_at_tick (double tick) const; @@ -369,10 +376,15 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible void remove_meter (const MeterSection&, bool send_signal); framepos_t compute_replacement_tempo_section (TempoSection* section, const double& tempo, const double& beat); + Metrics imagine_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame, const double& beat); + Metrics imagine_new_order (MeterSection* section, const Meter& mt, const framepos_t& frame, 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& 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_meter (MeterSection*, const Meter& mt, const framepos_t& where, const double& beat); - void gui_set_tempo_frame (TempoSection&, framepos_t where, double beat); void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); void replace_meter (const MeterSection&, const Meter&, const framepos_t& frame); diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index e2a2efd91e..c263f37387 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -216,7 +216,7 @@ TempoSection::tempo_at_frame (framepos_t f, framecnt_t frame_rate) const } /** returns the zero-based frame (relative to session) - where the tempo occurs. + where the tempo occurs in this section. note that the tempo map may have multiple such values. */ framepos_t TempoSection::frame_at_tempo (double bpm, framecnt_t frame_rate) const @@ -227,6 +227,31 @@ TempoSection::frame_at_tempo (double bpm, framecnt_t frame_rate) const return minute_to_frame (time_at_tick_tempo (bpm * BBT_Time::ticks_per_beat), frame_rate) + frame(); } +/** returns the tempo at the zero-based (relative to session) frame. +*/ +double +TempoSection::tempo_at_beat (double b) const +{ + + if (_type == Constant) { + return beats_per_minute(); + } + + return tick_tempo_at_tick ((b - beat()) * BBT_Time::ticks_per_beat) / BBT_Time::ticks_per_beat; +} + +/** returns the zero-based frame (relative to session) + where the tempo occurs in this section. note that the tempo map may have multiple such values. +*/ +double +TempoSection::beat_at_tempo (double bpm) const +{ + if (_type == Constant) { + return 0; + } + + return (tick_at_tick_tempo (bpm * BBT_Time::ticks_per_beat) / BBT_Time::ticks_per_beat) + beat(); +} /** returns the zero-based tick (relative to session origin) @@ -396,6 +421,20 @@ TempoSection::time_at_tick_tempo (double tick_tempo) const return log (tick_tempo / ticks_per_minute()) / _c_func; } +/* tick at tempo in tpm */ +double +TempoSection::tick_at_tick_tempo (double tick_tempo) const +{ + return (tick_tempo - ticks_per_minute()) / _c_func; +} + +/* tempo in tpm at tick */ +double +TempoSection::tick_tempo_at_tick (double tick) const +{ + return (tick * _c_func) + ticks_per_minute(); +} + /* tick at time in minutes */ double TempoSection::tick_at_time (double time) const @@ -947,89 +986,142 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const frame PropertyChanged (PropertyChange ()); } -void -TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double beat_where) +Metrics +TempoMap::imagine_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame, const double& beat) { - { - Glib::Threads::RWLock::WriterLock lm (lock); + Metrics imaginary (metrics); - if (ts.position_lock_style() == MusicTime) { - std::cerr << "Music " << " beat where : " << beat_where << " frame : " << frame <<std::endl; - /* MusicTime */ - ts.set_beat (beat_where); - Metrics::const_iterator i; - - TempoSection* prev_ts = 0; - MetricSectionSorter cmp; - metrics.sort (cmp); - for (i = metrics.begin(); i != metrics.end(); ++i) { - TempoSection* t; - if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + TempoSection* prev_ts = 0; + TempoSection* t; - if (t->beat() >= beat_where) { - break; - } + /*set frame and sort */ + section->set_frame (frame); + MetricSectionFrameSorter fcmp; + imaginary.sort (fcmp); + /* recompute */ + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((t = dynamic_cast<TempoSection*> (*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)); 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)); + } 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; + } + } + /* to do - check precision using _at_tempo() methods */ +/* + prev_ts = 0; + std::cerr << "dumping imaginary order ------" << std::endl;; + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + if (prev_ts) { - prev_ts->set_c_func_from_tempo_and_beat (ts.beats_per_minute(), ts.beat(), _frame_rate); - ts.set_frame (prev_ts->frame_at_beat (ts.beat(), _frame_rate)); - } else { - std::cerr << "Audio " << " beat where : " << beat_where << " frame : " << frame <<std::endl; + 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 << " ------" << std::endl;; - /*AudioTime*/ - ts.set_frame (frame); - MetricSectionFrameSorter fcmp; - metrics.sort (fcmp); + } + prev_ts = t; + } + } + std::cerr << "end dump ------"; +*/ + return imaginary; +} - Metrics::const_iterator i; - TempoSection* prev_ts = 0; - TempoSection* next_ts = 0; +Metrics +TempoMap::imagine_new_order(MeterSection* section, const Meter& mt, const framepos_t& frame, const double& beat) +{ + /* incomplete */ + Metrics imaginary (metrics); - for (i = metrics.begin(); i != metrics.end(); ++i) { - TempoSection* t; - if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { - if (t->frame() == frame) { - continue; - } - if (frame < t->frame()) { - next_ts = t; - break; - } + MeterSection* prev_ms = 0; + MeterSection* m; + MeterSection* our_section = 0; + framepos_t ret = 0; + MetricSectionSorter cmp; - prev_ts = t; + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((m = dynamic_cast<MeterSection*> (*i)) != 0) { + if (prev_ms) { + if (section->beat() == m->beat()) { + our_section = m; + continue; + } + if (beat < m->beat()){ + pair<double, BBT_Time> b_bbt = make_pair (beat, BBT_Time (1, 1, 0)); + our_section->set_beat (b_bbt); + our_section->set_frame (frame_at_beat_locked (beat)); + break; } - } - if (prev_ts) { - /* set the start beat - we need to reset the function constant before beat calculations make sense*/ - prev_ts->set_c_func (prev_ts->compute_c_func (ts.beats_per_minute(), frame, _frame_rate)); - double beats = prev_ts->beat_at_frame (frame, _frame_rate); - - if (next_ts) { - if (next_ts->beat() < beats) { - /* with frame-based editing, it is possible to get in a - situation where if the tempo was placed at the mouse pointer frame, - the following music-based tempo would jump to an earlier frame, - changing the odering. - in this case, we need some kind of tempo map speculator. - */ - } else if (prev_ts->beat() > beats) { - ts.set_beat (prev_ts->beat()); - } else { - ts.set_beat (beats); - } + if (m->position_lock_style() == MusicTime) { + m->set_frame (frame_at_beat_locked (m->beat())); } else { - ts.set_beat (beats); - ts.set_c_func (0.0); + pair<double, BBT_Time> b_bbt = make_pair (beat_at_frame_locked (m->frame()), BBT_Time (1, 1, 0)); + m->set_beat (b_bbt); + } + } + prev_ms = m; + } + } + /* now we do the whole thing again because audio-locked sections will have caused a re-order */ + prev_ms = 0; + metrics.sort (cmp); + for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) { + if ((m = dynamic_cast<MeterSection*> (*i)) != 0) { + if (prev_ms) { + if (section->beat() == m->beat()) { + continue; + } + if (beat < m->beat()){ + ret = frame_at_beat (beat); + section->set_frame (ret); + prev_ms = section; + break; + } + if (m->position_lock_style() == MusicTime) { + m->set_frame (frame_at_beat (m->beat())); + } else { + pair<double, BBT_Time> b_bbt = make_pair (beat_at_frame_locked (m->frame()), BBT_Time (1, 1, 0)); + m->set_beat (b_bbt); } - MetricSectionSorter cmp; - metrics.sort (cmp); } + prev_ms = m; } + } + + if (!ret) { + pair<double, BBT_Time> b_bbt = make_pair (beat, BBT_Time (1, 1, 0)); + section->set_beat (b_bbt); + section->set_frame (frame_at_beat_locked (beat)); + } + return imaginary; +} + +void +TempoMap::gui_move_tempo (TempoSection* ts, const Tempo& bpm, const framepos_t& frame, const double& beat_where) +{ + { + Glib::Threads::RWLock::WriterLock lm (lock); + Metrics new_order = imagine_new_order (ts, bpm, frame, beat_where); + metrics.clear(); + metrics = new_order; recompute_map (false); } @@ -1038,6 +1130,13 @@ TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double beat_ } void +TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const framepos_t& frame, const double& beat_where) +{ + Glib::Threads::RWLock::WriterLock lm (lock); + Metrics imaginary = imagine_new_order (ms, mt, frame, beat_where); +} + +void TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Type type) { { |