diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index d7cec55753..4c0606e26c 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1723,6 +1723,11 @@ private: PBD::Signal0 EditorFreeze; PBD::Signal0 EditorThaw; + void begin_tempo_map_edit (); + void abort_tempo_map_edit (); + void commit_tempo_map_edit (); + void mid_tempo_change (); + private: friend class DragManager; friend class EditorRouteGroups; @@ -1777,8 +1782,8 @@ private: void remove_tempo_marker (ArdourCanvas::Item*); void remove_meter_marker (ArdourCanvas::Item*); - gint real_remove_tempo_marker (Temporal::TempoPoint*); - gint real_remove_meter_marker (Temporal::MeterPoint*); + gint real_remove_tempo_marker (Temporal::TempoPoint const *); + gint real_remove_meter_marker (Temporal::MeterPoint const *); void edit_tempo_marker (TempoMarker&); void edit_meter_marker (MeterMarker&); @@ -1834,22 +1839,26 @@ private: Gtk::Menu* new_transport_marker_menu; ArdourCanvas::Item* marker_menu_item; - typedef std::list Marks; - Marks metric_marks; - - typedef std::list Curves; - Curves tempo_curves; + typedef std::list Marks; + Marks tempo_marks; + Marks meter_marks; + Marks bbt_marks; void remove_metric_marks (); void draw_metric_marks (Temporal::TempoMap::Metrics const & metrics); + void draw_tempo_marks (); + void draw_meter_marks (); + void draw_bbt_marks (); void compute_current_bbt_points (Temporal::TempoMapPoints& grid, samplepos_t left, samplepos_t right); void reassociate_metric_markers (Temporal::TempoMap::SharedPtr const &); - void reassociate_metric_marker (Temporal::TempoMap::SharedPtr const & tmap, Temporal::TempoMap::Metrics & metric, ArdourMarker& marker); - void begin_tempo_map_edit (); - void abort_tempo_map_edit (); - void commit_tempo_map_edit (); + void reassociate_metric_marker (Temporal::TempoMap::SharedPtr const & tmap, Temporal::TempoMap::Metrics & metric, MetricMarker& marker); + void make_bbt_marker (Temporal::MusicTimePoint const *); + void make_meter_marker (Temporal::MeterPoint const *); + void make_tempo_marker (Temporal::TempoPoint const * ts, double& min_tempo, double& max_tempo, Temporal::TempoPoint const *& prev_ts, uint32_t tc_color, samplecnt_t sr); + void update_tempo_curves (double min_tempo, double max_tempo, samplecnt_t sr); + void tempo_map_changed (); void redisplay_grid (bool immediate_redraw); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 0a5f4b1a9d..c67798fa1f 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3600,73 +3600,15 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) TempoMap::SharedPtr map (TempoMap::use()); if (first_move) { - - // mvc drag - create a dummy marker to catch events, hide it. - - char name[64]; - snprintf (name, sizeof (name), "%.2f", _marker->tempo().note_types_per_minute()); - - _marker = new TempoMarker ( - *_editor, - *_editor->tempo_group, - UIConfiguration::instance().color ("tempo marker"), - name, - _marker->tempo() - ); - - /* use the new marker for the grab */ - swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME); - _marker->hide(); - /* get current state */ _before_state = &map->get_state(); - - if (!_copy) { - - _editor->begin_reversible_command (_("move tempo mark")); - - } else { - - timepos_t const pointer = adjusted_current_time (event, false); - BBT_Time pointer_bbt = map->bbt_at (pointer); - Temporal::TempoMetric metric = map->metric_at (pointer); - Temporal::MeterPoint const & meter = metric.meter(); - Temporal::TempoPoint const & tempo = metric.tempo(); - BBT_Time bbt = tempo.bbt(); - - /* we can't add a tempo where one currently exists */ - if (bbt < pointer_bbt) { - bbt = meter.bbt_add (bbt, BBT_Offset (0, 1, 0)); - } else { - bbt = meter.bbt_add (bbt, BBT_Offset (0, -1, 0)); - } - - _editor->begin_reversible_command (_("copy tempo mark")); - - timepos_t pos; - - if (map->time_domain() == AudioTime) { - pos = timepos_t (map->sample_at (bbt)); - } else { - pos = timepos_t (map->quarters_at (bbt)); - } - - _marker->reset_tempo (map->set_tempo (tempo, pos)); - -#warning paul, need a return status from set_tempo -#if 0 - if (!) { - aborted (true); - return; - } -#endif - } + _editor->begin_reversible_command (_("move tempo mark")); } if (ArdourKeyboard::indicates_constraint (event->button.state) && ArdourKeyboard::indicates_copy (event->button.state)) { double new_bpm = max (1.5, _grab_bpm.end_note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); stringstream strs; - map->change_tempo (_marker->tempo(), Tempo (_marker->tempo().note_types_per_minute(), _marker->tempo().note_type(), new_bpm)); + map->change_tempo (const_cast(_marker->tempo()), Tempo (_marker->tempo().note_types_per_minute(), _marker->tempo().note_type(), new_bpm)); strs << "end:" << fixed << setprecision(3) << new_bpm; show_verbose_cursor_text (strs.str()); @@ -3674,31 +3616,19 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) /* use vertical movement to alter tempo .. should be log */ double new_bpm = max (1.5, _grab_bpm.note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0)); stringstream strs; - map->change_tempo (_marker->tempo(), Tempo (new_bpm, _marker->tempo().note_type(), _marker->tempo().end_note_types_per_minute())); + map->change_tempo (const_cast(_marker->tempo()), Tempo (new_bpm, _marker->tempo().note_type(), _marker->tempo().end_note_types_per_minute())); strs << "start:" << fixed << setprecision(3) << new_bpm; show_verbose_cursor_text (strs.str()); } else if (_movable) { - timepos_t pos = adjusted_current_time (event); - - std::cerr << " going to move " << &_marker->tempo() << std::endl; map->move_tempo (_marker->tempo(), pos, false); - - show_verbose_cursor_time (_marker->tempo().time()); - } - - - if (_movable && (!first_move || !_copy)) { - - timepos_t pos = adjusted_current_time (event); - - map->move_tempo (_marker->tempo(), pos, false); - show_verbose_cursor_time (_marker->tempo().time()); + _editor->mid_tempo_change (); } } + void TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) { @@ -3727,10 +3657,6 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) _editor->session()->add_command (new MementoCommand (new Temporal::TempoMap::MementoBinder(), _before_state, &after)); _editor->commit_reversible_command (); - - // delete the dummy marker we used for visual representation while moving. - // a new visual marker will show up automatically. - delete _marker; } void diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 0c51ef9d4a..bce6d88b57 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -875,7 +875,7 @@ public: private: TempoMarker* _marker; - Temporal::TempoPoint* _real_section; + Temporal::TempoPoint const * _real_section; bool _copy; bool _movable; @@ -968,7 +968,7 @@ public: private: Temporal::Beats _grab_qn; - Temporal::TempoPoint* _tempo; + Temporal::TempoPoint const * _tempo; XMLNode* _before_state; bool _drag_valid; }; diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index 8bb5ef51b3..25ef61eee0 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -1531,9 +1531,9 @@ Editor::marker_menu_edit () dynamic_cast_marker_object (marker_menu_item->get_data ("marker"), &mm, &tm); if (mm) { - edit_meter_section (mm->meter()); + edit_meter_section (const_cast(mm->meter())); } else if (tm) { - edit_tempo_section (tm->tempo()); + edit_tempo_section (const_cast(tm->tempo())); } } @@ -1567,11 +1567,11 @@ Editor::toggle_tempo_type () TempoMap::SharedPtr tmap (TempoMap::write_copy()); reassociate_metric_markers (tmap); - Temporal::TempoPoint & tempo = tm->tempo(); + Temporal::TempoPoint const & tempo = tm->tempo(); XMLNode &before = tmap->get_state(); - tmap->set_ramped (tempo, !tempo.ramped()); + tmap->set_ramped (const_cast(tempo), !tempo.ramped()); XMLNode &after = tmap->get_state(); _session->add_command (new MementoCommand (new Temporal::TempoMap::MementoBinder(), &before, &after)); @@ -1595,9 +1595,9 @@ Editor::toggle_tempo_clamped () XMLNode &before = tmap->get_state(); reassociate_metric_markers (tmap); - Temporal::Tempo & tempo (tm->tempo()); + Temporal::Tempo const & tempo (tm->tempo()); - tempo.set_clamped (!tempo.clamped()); + const_cast(tempo).set_clamped (!tempo.clamped()); XMLNode &after = tmap->get_state(); _session->add_command (new MementoCommand (new Temporal::TempoMap::MementoBinder(), &before, &after)); @@ -1622,9 +1622,9 @@ Editor::ramp_to_next_tempo () XMLNode &before = tmap->get_state(); reassociate_metric_markers (tmap); - Temporal::TempoPoint & tempo (tm->tempo()); + Temporal::TempoPoint const & tempo (tm->tempo()); - tmap->set_ramped (tempo, !tempo.ramped()); + tmap->set_ramped (const_cast(tempo), !tempo.ramped()); XMLNode &after = tmap->get_state(); _session->add_command (new MementoCommand (new Temporal::TempoMap::MementoBinder(), &before, &after)); diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc index 5e4f4a6d9b..4329f0e030 100644 --- a/gtk2_ardour/editor_tempodisplay.cc +++ b/gtk2_ardour/editor_tempodisplay.cc @@ -73,36 +73,40 @@ Editor::remove_metric_marks () { /* don't delete these while handling events, just punt till the GUI is idle */ - for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) { - delete_when_idle (*x); + for (auto & m : tempo_marks) { + delete_when_idle (m); + } + for (auto & m : meter_marks) { + delete_when_idle (m); + } + for (auto & m : bbt_marks) { + delete_when_idle (m); } - metric_marks.clear (); - for (Curves::iterator x = tempo_curves.begin(); x != tempo_curves.end(); ++x) { - delete (*x); - } - tempo_curves.clear (); + tempo_marks.clear (); + meter_marks.clear (); + bbt_marks.clear (); } -struct CurveComparator { - bool operator() (TempoCurve const * a, TempoCurve const * b) { - return a->tempo().sclock() < b->tempo().sclock(); - } -}; - void Editor::reassociate_metric_markers (TempoMap::SharedPtr const & tmap) { TempoMap::Metrics metrics; tmap->get_metrics (metrics); - for (auto & marker : metric_marks) { - reassociate_metric_marker (tmap, metrics, *marker); + for (auto & m : tempo_marks) { + reassociate_metric_marker (tmap, metrics, *m); + } + for (auto & m : meter_marks) { + reassociate_metric_marker (tmap, metrics, *m); + } + for (auto & m : bbt_marks) { + reassociate_metric_marker (tmap, metrics, *m); } } void -Editor::reassociate_metric_marker (TempoMap::SharedPtr const & tmap, TempoMap::Metrics & metrics, ArdourMarker& marker) +Editor::reassociate_metric_marker (TempoMap::SharedPtr const & tmap, TempoMap::Metrics & metrics, MetricMarker& marker) { TempoMarker* tm; MeterMarker* mm; @@ -157,70 +161,266 @@ Editor::reassociate_metric_marker (TempoMap::SharedPtr const & tmap, TempoMap::M } void -Editor::draw_metric_marks (TempoMap::Metrics const & metrics) +Editor::make_bbt_marker (MusicTimePoint const * mtp) +{ + if (mtp->map().time_domain() == BeatTime) { + bbt_marks.push_back (new BBTMarker (*this, *bbt_ruler, UIConfiguration::instance().color ("meter marker music"), "bar!", *mtp)); + } else { + bbt_marks.push_back (new BBTMarker (*this, *bbt_ruler, UIConfiguration::instance().color ("meter marker"), "foo!", *mtp)); + } +} + +void +Editor::make_meter_marker (Temporal::MeterPoint const * ms) +{ + char buf[64]; + + snprintf (buf, sizeof(buf), "%d/%d", ms->divisions_per_bar(), ms->note_value ()); + if (ms->map().time_domain() == BeatTime) { + meter_marks.push_back (new MeterMarker (*this, *meter_group, UIConfiguration::instance().color ("meter marker music"), buf, *ms)); + } else { + meter_marks.push_back (new MeterMarker (*this, *meter_group, UIConfiguration::instance().color ("meter marker"), buf, *ms)); + } +} + +void +Editor::make_tempo_marker (Temporal::TempoPoint const * ts, double& min_tempo, double& max_tempo, TempoPoint const *& prev_ts, uint32_t tc_color, samplecnt_t sr) +{ + max_tempo = max (max_tempo, ts->note_types_per_minute()); + max_tempo = max (max_tempo, ts->end_note_types_per_minute()); + min_tempo = min (min_tempo, ts->note_types_per_minute()); + min_tempo = min (min_tempo, ts->end_note_types_per_minute()); + + const std::string tname (X_("")); + char const * color_name; + + /* XXX not sure this is the right thing to do here (differentiate time + * domains with color). + */ + + if (ts->map().time_domain() == BeatTime) { + color_name = X_("tempo marker music"); + } else { + color_name = X_("tempo marker music"); + } + + tempo_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color (color_name), tname, *ts, ts->sample (sr), tc_color)); + + /* XXX the point of this code was "a jump in tempo by more than 1 ntpm results in a red + tempo mark pointer." (3a7bc1fd3f32f0) + */ + + if (prev_ts && abs (prev_ts->end_note_types_per_minute() - ts->note_types_per_minute()) < 1.0) { + tempo_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker music")); + } else { + tempo_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker")); + } + + prev_ts = ts; +} + +void +Editor::draw_metric_marks (Temporal::TempoMap::Metrics const &) +{ + draw_tempo_marks (); + draw_meter_marks (); + draw_bbt_marks (); +} + +void +Editor::draw_tempo_marks () { if (!_session) { return; } - char buf[64]; - TempoPoint* prev_ts = 0; + const uint32_t tc_color = UIConfiguration::instance().color ("tempo curve"); + const samplecnt_t sr (_session->sample_rate()); + TempoPoint const * prev_ts = 0; + Temporal::TempoMap::SharedPtr tmap (TempoMap::use()); + TempoMap::Tempos const & tempi (tmap->tempos()); + TempoMap::Tempos::const_iterator t = tempi.begin(); + Marks::iterator mm = tempo_marks.begin(); double max_tempo = 0.0; double min_tempo = DBL_MAX; - const samplecnt_t sr (_session->sample_rate()); - remove_metric_marks (); // also clears tempo curves + std::cerr << "**** BEGIN DRAW TEMPO\n"; - for (TempoMap::Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) { - Temporal::MeterPoint *ms; - Temporal::TempoPoint *ts; - Temporal::MusicTimePoint *mtp; + while (t != tempi.end() && mm != tempo_marks.end()) { - /* must check MusicTimePoint first, since it IS-A TempoPoint - * and MeterPoint. - */ + Temporal::Point const & mark_point ((*mm)->point()); + Temporal::TempoPoint const & metric_point (*t); - if ((mtp = dynamic_cast(*i)) != 0) { + std::cerr << "\tmark @ " << mark_point.sclock() << " tempo @ " << metric_point.sclock() << std::endl; - if (mtp->map().time_domain() == BeatTime) { - metric_marks.push_back (new BBTMarker (*this, *bbt_ruler, UIConfiguration::instance().color ("meter marker music"), "bar!", *mtp)); - } else { - metric_marks.push_back (new BBTMarker (*this, *bbt_ruler, UIConfiguration::instance().color ("meter marker"), "foo!", *mtp)); - } - } else if ((ms = dynamic_cast(*i)) != 0) { - snprintf (buf, sizeof(buf), "%d/%d", ms->divisions_per_bar(), ms->note_value ()); - if (ms->map().time_domain() == BeatTime) { - metric_marks.push_back (new MeterMarker (*this, *meter_group, UIConfiguration::instance().color ("meter marker music"), buf, *ms)); - } else { - metric_marks.push_back (new MeterMarker (*this, *meter_group, UIConfiguration::instance().color ("meter marker"), buf, *ms)); - } - } else if ((ts = dynamic_cast(*i)) != 0) { - max_tempo = max (max_tempo, ts->note_types_per_minute()); - max_tempo = max (max_tempo, ts->end_note_types_per_minute()); - min_tempo = min (min_tempo, ts->note_types_per_minute()); - min_tempo = min (min_tempo, ts->end_note_types_per_minute()); - uint32_t const tc_color = UIConfiguration::instance().color ("tempo curve"); + if (mark_point.sclock() < metric_point.sclock()) { - tempo_curves.push_back (new TempoCurve (*this, *tempo_group, tc_color, *ts, ts->sample (sr), false)); + /* advance through markers, deleting the unused ones */ - const std::string tname (X_("")); - if (ts->map().time_domain() == BeatTime) { - metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker music"), tname, *ts)); + std::cerr << "\tDeleting marker that doesn't match a tempo point\n"; + delete *mm; + mm = tempo_marks.erase (mm); - } else { - metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker"), tname, *ts)); - } - if (prev_ts && abs (prev_ts->end_note_types_per_minute() - ts->note_types_per_minute()) < 1.0) { - metric_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker music")); - } else { - metric_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker")); - } - prev_ts = ts; + + } else if (metric_point.sclock() < mark_point.sclock()) { + + std::cerr << "\tCreating a marker for " << metric_point << " @ " << metric_point.sample (sr) << " next marker @ " << mark_point.sample (sr) << std::endl; + make_tempo_marker (&metric_point, min_tempo, max_tempo, prev_ts, tc_color, sr); + ++t; + + } else { + /* marker represents an existing point, update text, properties etc */ + /* XXX left/right text stuff */ + // (*mm)->set_name ((*m)->name()); + std::cerr << "\tMoving marker to " << t->time() << std::endl; + (*mm)->set_position (t->time()); + + max_tempo = max (max_tempo, t->note_types_per_minute()); + max_tempo = max (max_tempo, t->end_note_types_per_minute()); + min_tempo = min (min_tempo, t->note_types_per_minute()); + min_tempo = min (min_tempo, t->end_note_types_per_minute()); + + ++t; + ++mm; } - } - tempo_curves.sort (CurveComparator()); + if ((t == tempi.end()) && (mm != tempo_marks.end())) { + while (mm != tempo_marks.end()) { + std::cerr << "\tdrop excess tempo marker @ " << (*mm)->point().time() << std::endl; + delete *mm; + mm = tempo_marks.erase (mm); + } + } + + if ((mm == tempo_marks.end()) && (t != tempi.end())) { + while (t != tempi.end()) { + std::cerr << "\tmake new tempo marker @ " << t->time() << std::endl; + make_tempo_marker (&*t, min_tempo, max_tempo, prev_ts, tc_color, sr); + ++t; + } + } + + update_tempo_curves (min_tempo, max_tempo, sr); + + for (auto & m : tempo_marks) { + TempoMarker* tm = static_cast (m); + tm->update_height_mark ((tm->tempo().note_types_per_minute() - min_tempo) / max (10.0, max_tempo - min_tempo)); + std::cerr << "TEMPO:\n\t" << tm->tempo() << std::endl; + } +} + +void +Editor::draw_meter_marks () +{ + if (!_session) { + return; + } + + Temporal::TempoMap::SharedPtr tmap (TempoMap::use()); + TempoMap::Meters const & meters (tmap->meters()); + TempoMap::Meters::const_iterator m = meters.begin(); + Marks::iterator mm = meter_marks.begin(); + + while (m != meters.end() && mm != meter_marks.end()) { + + Temporal::Point const & mark_point ((*mm)->point()); + Temporal::MeterPoint const & metric_point (*m); + + if (mark_point.sclock() < metric_point.sclock()) { + + /* advance through markers, deleting the unused ones */ + + delete *mm; + mm = meter_marks.erase (mm); + + } else if (metric_point.sclock() < mark_point.sclock()) { + + make_meter_marker (&metric_point); + ++m; + + } else { + /* marker represents an existing point, update text, properties etc */ + /* XXX left/right text stuff */ + // (*mm)->set_name ((*m)->name()); + (*mm)->set_position (m->time()); + ++m; + ++mm; + } + } + + if ((m == meters.end()) && (mm != meter_marks.end())) { + while (mm != meter_marks.end()) { + delete *mm; + mm = meter_marks.erase (mm); + } + } + + if ((mm == tempo_marks.end()) && (m != meters.end())) { + while (m != meters.end()) { + make_meter_marker (&*m); + ++m; + } + } +} + +void +Editor::draw_bbt_marks () +{ + if (!_session) { + return; + } + + Temporal::TempoMap::SharedPtr tmap (TempoMap::use()); + TempoMap::MusicTimes const & bartimes (tmap->bartimes()); + TempoMap::MusicTimes::const_iterator m = bartimes.begin(); + Marks::iterator mm = bbt_marks.begin(); + + while (m != bartimes.end() && mm != bbt_marks.end()) { + + Temporal::Point const & mark_point ((*mm)->point()); + Temporal::MeterPoint const & metric_point (*m); + + if (mark_point.sclock() < metric_point.sclock()) { + + /* advance through markers, deleting the unused ones */ + + delete *mm; + mm = bbt_marks.erase (mm); + + } else if (metric_point.sclock() < mark_point.sclock()) { + + make_meter_marker (&metric_point); + ++m; + + } else { + /* marker represents an existing point, update text, properties etc */ + /* XXX left/right text stuff */ + // (*mm)->set_name ((*m)->name()); + (*mm)->set_position (m->time()); + ++m; + ++mm; + } + } + + if ((m == bartimes.end()) && (mm != bbt_marks.end())) { + while (mm != bbt_marks.end()) { + delete *mm; + mm = bbt_marks.erase (mm); + } + } + + if ((mm == tempo_marks.end()) && (m != bartimes.end())) { + while (m != bartimes.end()) { + make_meter_marker (&*m); + ++m; + } + } +} + +void +Editor::update_tempo_curves (double min_tempo, double max_tempo, samplecnt_t sr) +{ const double min_tempo_range = 5.0; const double tempo_delta = fabs (max_tempo - min_tempo); @@ -229,31 +429,28 @@ Editor::draw_metric_marks (TempoMap::Metrics const & metrics) min_tempo += tempo_delta - min_tempo_range; } - for (Curves::iterator x = tempo_curves.begin(); x != tempo_curves.end(); ) { - Curves::iterator tmp = x; - (*x)->set_max_tempo (max_tempo); - (*x)->set_min_tempo (min_tempo); + for (Marks::iterator m = tempo_marks.begin(); m != tempo_marks.end(); ++m) { + + TempoMarker* tm = static_cast(*m); + Marks::iterator tmp = m; ++tmp; - if (tmp != tempo_curves.end()) { - (*x)->set_position ((*x)->tempo().sample(sr), (*tmp)->tempo().sample(sr)); + + TempoCurve& curve (tm->curve()); + + curve.set_max_tempo (max_tempo); + curve.set_min_tempo (min_tempo); + + if (tmp != tempo_marks.end()) { + TempoMarker* nxt = static_cast(*tmp); + curve.set_duration (nxt->tempo().sample(sr) - tm->tempo().sample(sr)); } else { - (*x)->set_position ((*x)->tempo().sample(sr), UINT32_MAX); + curve.set_duration (samplecnt_t (UINT32_MAX)); } - if (!(*x)->tempo().active()) { - (*x)->hide(); + if (!tm->tempo().active()) { + curve.hide(); } else { - (*x)->show(); - } - - ++x; - } - - for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) { - TempoMarker* tempo_marker; - - if ((tempo_marker = dynamic_cast (*x)) != 0) { - tempo_marker->update_height_mark ((tempo_marker->tempo().note_types_per_minute() - min_tempo) / max (10.0, max_tempo - min_tempo)); + curve.show(); } } } @@ -294,12 +491,13 @@ Editor::tempo_curve_selected (Temporal::TempoPoint const * ts, bool yn) return; } - for (Curves::iterator x = tempo_curves.begin(); x != tempo_curves.end(); ++x) { - if (&(*x)->tempo() == ts) { + for (Marks::iterator x = tempo_marks.begin(); x != tempo_marks.end(); ++x) { + TempoMarker* tm = static_cast (*x); + if (&tm->tempo() == ts) { if (yn) { - (*x)->set_color_rgba (UIConfiguration::instance().color ("location marker")); + tm->curve().set_color_rgba (UIConfiguration::instance().color ("location marker")); } else { - (*x)->set_color_rgba (UIConfiguration::instance().color ("tempo curve")); + tm->curve().set_color_rgba (UIConfiguration::instance().color ("tempo curve")); } break; } @@ -565,17 +763,17 @@ Editor::edit_tempo_section (TempoPoint& section) void Editor::edit_tempo_marker (TempoMarker& tm) { - edit_tempo_section (tm.tempo()); + edit_tempo_section (const_cast(tm.tempo())); } void Editor::edit_meter_marker (MeterMarker& mm) { - edit_meter_section (mm.meter()); + edit_meter_section (const_cast(mm.meter())); } gint -Editor::real_remove_tempo_marker (TempoPoint *section) +Editor::real_remove_tempo_marker (TempoPoint const * section) { begin_reversible_command (_("remove tempo mark")); TempoMap::SharedPtr tmap (TempoMap::write_copy()); @@ -612,7 +810,7 @@ Editor::remove_meter_marker (ArdourCanvas::Item* item) } gint -Editor::real_remove_meter_marker (Temporal::MeterPoint *section) +Editor::real_remove_meter_marker (Temporal::MeterPoint const * section) { begin_reversible_command (_("remove tempo mark")); TempoMap::SharedPtr tmap (TempoMap::write_copy()); @@ -651,3 +849,10 @@ Editor::commit_tempo_map_edit () TempoMap::SharedPtr tmap (TempoMap::use()); TempoMap::update (tmap); } + +void +Editor::mid_tempo_change () +{ + std::cerr << "============== MID TEMPO\n"; + draw_tempo_marks (); +} diff --git a/gtk2_ardour/marker.cc b/gtk2_ardour/marker.cc index fdda34b748..910fc2e79c 100644 --- a/gtk2_ardour/marker.cc +++ b/gtk2_ardour/marker.cc @@ -51,6 +51,7 @@ #include "public_editor.h" #include "utils.h" #include "rgb_macros.h" +#include "tempo_curve.h" #include @@ -535,6 +536,7 @@ void ArdourMarker::set_position (timepos_t const & pos) { unit_position = editor.sample_to_pixel (pos.samples()) - _shift; + cerr << "marker @ " << this << " set pos to " << unit_position << endl; group->set_x_position (unit_position); setup_line (); _position = pos; @@ -631,18 +633,32 @@ ArdourMarker::set_right_label_limit (double p) } } +MetricMarker::MetricMarker (PublicEditor& ed, ArdourCanvas::Item& parent, guint32 rgba, const string& annotation, + Type type, timepos_t const & pos, bool handle_events) + : ArdourMarker (ed, parent, rgba, annotation, type, pos, false) +{ +} + /***********************************************************************/ -TempoMarker::TempoMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, - Temporal::TempoPoint& temp) - : ArdourMarker (editor, parent, rgba, text, Tempo, temp.time(), false) +TempoMarker::TempoMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, Temporal::TempoPoint const & temp, samplepos_t sample, uint32_t curve_color) + : MetricMarker (editor, parent, rgba, text, Tempo, temp.time(), false) , _tempo (&temp) { group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_marker_event), group, this)); + /* points[1].x gives the width of the marker */ + _curve = new TempoCurve (editor, *group, curve_color, temp, true, (*points)[1].x); } TempoMarker::~TempoMarker () { + delete _curve; +} + +TempoCurve& +TempoMarker::curve() +{ + return *_curve; } void @@ -666,16 +682,21 @@ TempoMarker::update_height_mark (const double ratio) } void -TempoMarker::reset_tempo (Temporal::TempoPoint & t) +TempoMarker::reset_tempo (Temporal::TempoPoint const & t) { _tempo = &t; } +Temporal::Point const & +TempoMarker::point() const +{ + return *_tempo; +} /***********************************************************************/ -MeterMarker::MeterMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, Temporal::MeterPoint& m) - : ArdourMarker (editor, parent, rgba, text, Meter, m.time(), false) +MeterMarker::MeterMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, Temporal::MeterPoint const & m) + : MetricMarker (editor, parent, rgba, text, Meter, m.time(), false) , _meter (&m) { group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_meter_marker_event), group, this)); @@ -686,15 +707,21 @@ MeterMarker::~MeterMarker () } void -MeterMarker::reset_meter (Temporal::MeterPoint & m) +MeterMarker::reset_meter (Temporal::MeterPoint const & m) { _meter = &m; } +Temporal::Point const & +MeterMarker::point() const +{ + return *_meter; +} + /***********************************************************************/ -BBTMarker::BBTMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, Temporal::MusicTimePoint& p) - : ArdourMarker (editor, parent, rgba, text, BBTPosition, p.time(), false) +BBTMarker::BBTMarker (PublicEditor& editor, ArdourCanvas::Item& parent, guint32 rgba, const string& text, Temporal::MusicTimePoint const & p) + : MetricMarker (editor, parent, rgba, text, BBTPosition, p.time(), false) , _point (&p) { group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_bbt_marker_event), group, this)); @@ -705,7 +732,13 @@ BBTMarker::~BBTMarker () } void -BBTMarker::reset_point (Temporal::MusicTimePoint & p) +BBTMarker::reset_point (Temporal::MusicTimePoint const & p) { _point = &p; } + +Temporal::Point const & +BBTMarker::point() const +{ + return *_point; +} diff --git a/gtk2_ardour/marker.h b/gtk2_ardour/marker.h index 7cef154858..dd67b14780 100644 --- a/gtk2_ardour/marker.h +++ b/gtk2_ardour/marker.h @@ -36,6 +36,7 @@ #include "canvas/types.h" namespace Temporal { + class Point; class TempoPoint; class MeterPoint; class MusicTimePoint; @@ -43,6 +44,7 @@ namespace Temporal { class PublicEditor; class RegionView; +class TempoCurve; /** Location Marker * @@ -156,47 +158,60 @@ private: ArdourMarker & operator= (ArdourMarker const &); }; -class TempoMarker : public ArdourMarker +class MetricMarker : public ArdourMarker { public: - TempoMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::TempoPoint&); + MetricMarker (PublicEditor& ed, ArdourCanvas::Item& parent, guint32 rgba, const std::string& annotation, Type type, Temporal::timepos_t const & pos, bool handle_events); + virtual Temporal::Point const & point() const = 0; +}; + +class TempoMarker : public MetricMarker +{ + public: + TempoMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::TempoPoint const &, samplepos_t sample, uint32_t curve_color); ~TempoMarker (); - void reset_tempo (Temporal::TempoPoint & t); + void reset_tempo (Temporal::TempoPoint const & t); - Temporal::TempoPoint& tempo() const { return *_tempo; } + Temporal::TempoPoint const & tempo() const { return *_tempo; } + Temporal::Point const & point() const; void update_height_mark (const double ratio); + TempoCurve& curve(); + private: - Temporal::TempoPoint* _tempo; + Temporal::TempoPoint const * _tempo; + TempoCurve* _curve; }; -class MeterMarker : public ArdourMarker +class MeterMarker : public MetricMarker { public: - MeterMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::MeterPoint&); + MeterMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::MeterPoint const &); ~MeterMarker (); - void reset_meter (Temporal::MeterPoint & m); + void reset_meter (Temporal::MeterPoint const & m); - Temporal::MeterPoint& meter() const { return *_meter; } + Temporal::MeterPoint const & meter() const { return *_meter; } + Temporal::Point const & point() const; private: - Temporal::MeterPoint* _meter; + Temporal::MeterPoint const * _meter; }; -class BBTMarker : public ArdourMarker +class BBTMarker : public MetricMarker { public: - BBTMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::MusicTimePoint&); + BBTMarker (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, const std::string& text, Temporal::MusicTimePoint const &); ~BBTMarker (); - void reset_point (Temporal::MusicTimePoint &); + void reset_point (Temporal::MusicTimePoint const &); - Temporal::MusicTimePoint& point() const { return *_point; } + Temporal::MusicTimePoint const & mt_point() const { return *_point; } + Temporal::Point const & point() const; private: - Temporal::MusicTimePoint* _point; + Temporal::MusicTimePoint const * _point; }; #endif /* __gtk_ardour_marker_h__ */ diff --git a/gtk2_ardour/tempo_curve.cc b/gtk2_ardour/tempo_curve.cc index 739b6c7251..713e326eab 100644 --- a/gtk2_ardour/tempo_curve.cc +++ b/gtk2_ardour/tempo_curve.cc @@ -44,17 +44,21 @@ PBD::Signal1 TempoCurve::CatchDeletion; static double curve_height = 13.0; -void TempoCurve::setup_sizes(const double timebar_height) +void +TempoCurve::setup_sizes(const double timebar_height) { - curve_height = floor (timebar_height) - 2.5; + const double ui_scale = UIConfiguration::instance ().get_ui_scale (); + curve_height = floor (timebar_height) - (2.5 * ui_scale); } + /* ignores Tempo note type - only note_types_per_minute is potentially curved */ -TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint32 rgba, TempoPoint& temp, samplepos_t sample, bool handle_events) +TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Item& parent, guint32 rgba, TempoPoint const & temp, bool handle_events, ArdourCanvas::Distance marker_width) : editor (ed) , _parent (&parent) , _curve (0) - , _shown (false) + , _duration (UINT32_MAX) + , _marker_width (marker_width) , _color (rgba) , _min_tempo (temp.note_types_per_minute()) , _max_tempo (temp.note_types_per_minute()) @@ -62,10 +66,8 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint , _start_text (0) , _end_text (0) { - sample_position = sample; - unit_position = editor.sample_to_pixel (sample); - - group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (unit_position, 1)); + /* XXX x arg for Duple should probably be marker width, passed in from owner */ + group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (marker_width, 1)); #ifdef CANVAS_DEBUG group->name = string_compose ("TempoCurve::group for %1", _tempo.note_types_per_minute()); #endif @@ -75,8 +77,7 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint _curve->name = string_compose ("TempoCurve::curve for %1", _tempo.note_types_per_minute()); #endif _curve->set_points_per_segment (3); - points = new ArdourCanvas::Points (); - _curve->set (*points); + _curve->set (points); _start_text = new ArdourCanvas::Text (group); _end_text = new ArdourCanvas::Text (group); @@ -116,18 +117,6 @@ TempoCurve::~TempoCurve () delete group; } -void TempoCurve::reparent(ArdourCanvas::Container & parent) -{ - group->reparent (&parent); - _parent = &parent; -} - -void -TempoCurve::canvas_height_set (double h) -{ - _canvas_height = h; -} - ArdourCanvas::Item& TempoCurve::the_item() const { @@ -135,42 +124,31 @@ TempoCurve::the_item() const } void -TempoCurve::set_position (samplepos_t sample, samplepos_t end_sample) +TempoCurve::set_duration (samplecnt_t duration) { - unit_position = editor.sample_to_pixel (sample); - group->set_x_position (unit_position); - sample_position = sample; - _end_sample = end_sample; + points.clear(); + points.push_back (ArdourCanvas::Duple (0.0, curve_height)); - points->clear(); - points = new ArdourCanvas::Points (); + ArdourCanvas::Coord duration_pixels = editor.sample_to_pixel (duration); - points->push_back (ArdourCanvas::Duple (0.0, curve_height)); + if (!_tempo.ramped()) { - if (sample >= end_sample) { - /* shouldn't happen but ..*/ const double tempo_at = _tempo.note_types_per_minute(); const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height); - points->push_back (ArdourCanvas::Duple (0.0, y_pos)); - points->push_back (ArdourCanvas::Duple (1.0, y_pos)); + points.push_back (ArdourCanvas::Duple (0.0, y_pos)); + points.push_back (ArdourCanvas::Duple (duration_pixels, y_pos)); - } else if (!_tempo.ramped()) { - const double tempo_at = _tempo.note_types_per_minute(); - const double y_pos = (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height); - - points->push_back (ArdourCanvas::Duple (0.0, y_pos)); - points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample), y_pos)); } else { - const samplepos_t sample_step = std::max ((end_sample - sample) / 5, (samplepos_t) 1); - samplepos_t current_sample = sample; + const samplepos_t sample_step = std::max ((duration) / 5, (samplepos_t) 1); + samplepos_t current_sample = 0; - while (current_sample < end_sample) { + while (current_sample < duration) { const double tempo_at = _tempo.note_types_per_minute_at_DOUBLE (timepos_t (current_sample)); const double y_pos = std::max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0); - points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (current_sample - sample), std::min (y_pos, curve_height))); + points.push_back (ArdourCanvas::Duple (editor.sample_to_pixel (current_sample), std::min (y_pos, curve_height))); current_sample += sample_step; } @@ -178,48 +156,49 @@ TempoCurve::set_position (samplepos_t sample, samplepos_t end_sample) const double tempo_at = _tempo.note_types_per_minute(); const double y_pos = std::max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0); - points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample), std::min (y_pos, curve_height))); + points.push_back (ArdourCanvas::Duple (duration_pixels, std::min (y_pos, curve_height))); } - _curve->set (*points); + _curve->set (points); char buf[10]; + snprintf (buf, sizeof (buf), "%.3f/%d", _tempo.note_types_per_minute(), _tempo.note_type()); _start_text->set (buf); snprintf (buf, sizeof (buf), "%.3f", _tempo.end_note_types_per_minute()); _end_text->set (buf); - _start_text->set_position (ArdourCanvas::Duple (10, .5 )); - _end_text->set_position (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample) - _end_text->text_width() - 10, .5 )); + const double ui_scale = UIConfiguration::instance ().get_ui_scale (); - if (_end_text->text_width() + _start_text->text_width() + 20 > editor.sample_to_pixel (end_sample - sample)) { + _start_text->set_position (ArdourCanvas::Duple (_marker_width + (10 * ui_scale), (.5 * ui_scale))); + _end_text->set_position (ArdourCanvas::Duple (duration_pixels - _end_text->text_width() - _marker_width - (10. * ui_scale), (.5 * ui_scale))); + + if (_end_text->text_width() + _start_text->text_width() + (20.0 * ui_scale) > duration_pixels) { _start_text->hide(); _end_text->hide(); } else { _start_text->show(); _end_text->show(); } + + _duration = duration; } void TempoCurve::reposition () { - set_position (sample_position, _end_sample); + set_duration (_duration); } void TempoCurve::show () { - _shown = true; - group->show (); } void TempoCurve::hide () { - _shown = false; - group->hide (); } diff --git a/gtk2_ardour/tempo_curve.h b/gtk2_ardour/tempo_curve.h index 956426d3c4..272769858e 100644 --- a/gtk2_ardour/tempo_curve.h +++ b/gtk2_ardour/tempo_curve.h @@ -40,7 +40,7 @@ class PublicEditor; class TempoCurve : public sigc::trackable { public: - TempoCurve (PublicEditor& editor, ArdourCanvas::Container &, guint32 rgba, Temporal::TempoPoint& temp, samplepos_t sample, bool handle_events); + TempoCurve (PublicEditor& editor, ArdourCanvas::Item &, guint32 rgba, Temporal::TempoPoint const & temp, bool handle_events , ArdourCanvas::Distance marker_width); ~TempoCurve (); static PBD::Signal1 CatchDeletion; @@ -48,19 +48,14 @@ public: static void setup_sizes (const double timebar_height); ArdourCanvas::Item& the_item() const; - void canvas_height_set (double); - void set_position (samplepos_t lower, samplepos_t upper); + void set_duration (ARDOUR::samplecnt_t duration); void set_color_rgba (uint32_t rgba); - samplepos_t position() const { return sample_position; } - - ArdourCanvas::Container* get_parent() { return _parent; } - void reparent (ArdourCanvas::Container& parent); void hide (); void show (); - Temporal::TempoPoint& tempo () const { return _tempo; } + Temporal::TempoPoint const & tempo () const { return _tempo; } void set_max_tempo (const double& max) { _max_tempo = max; } void set_min_tempo (const double& min) { _min_tempo = min; } @@ -68,17 +63,14 @@ public: protected: PublicEditor& editor; - ArdourCanvas::Container* _parent; + ArdourCanvas::Item* _parent; ArdourCanvas::Container* group; - ArdourCanvas::Points* points; + ArdourCanvas::Points points; ArdourCanvas::FramedCurve* _curve; - double unit_position; - samplepos_t sample_position; - samplepos_t _end_sample; - bool _shown; - double _canvas_height; - uint32_t _color; + ARDOUR::samplecnt_t _duration; + ArdourCanvas::Distance _marker_width; + uint32_t _color; void reposition (); @@ -91,7 +83,7 @@ private: double _min_tempo; double _max_tempo; - Temporal::TempoPoint& _tempo; + Temporal::TempoPoint const & _tempo; ArdourCanvas::Text* _start_text; ArdourCanvas::Text* _end_text; };