Substantial overhaul of tempo display code

Major changes: do not delete and recreate markers and curves for every tempo map
change, attach tempo curves directly to their (preceding) tempo marker, notable
cleanup of TempoCurve class to remove unnecessary members.

More tweaks expected since algorithm for matching markers and tempo map
points is not correct yet.
This commit is contained in:
Paul Davis 2022-01-18 19:45:18 -07:00
parent dbefba9904
commit c916d3d952
9 changed files with 445 additions and 286 deletions

View File

@ -1723,6 +1723,11 @@ private:
PBD::Signal0<void> EditorFreeze;
PBD::Signal0<void> 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<ArdourMarker*> Marks;
Marks metric_marks;
typedef std::list<TempoCurve*> Curves;
Curves tempo_curves;
typedef std::list<MetricMarker*> 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);

View File

@ -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<TempoPoint&>(_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<TempoPoint&>(_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<Temporal::TempoMap> (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

View File

@ -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;
};

View File

@ -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<Temporal::MeterPoint&>(mm->meter()));
} else if (tm) {
edit_tempo_section (tm->tempo());
edit_tempo_section (const_cast<Temporal::TempoPoint&>(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<Temporal::TempoPoint&>(tempo), !tempo.ramped());
XMLNode &after = tmap->get_state();
_session->add_command (new MementoCommand<Temporal::TempoMap> (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<Temporal::Tempo&>(tempo).set_clamped (!tempo.clamped());
XMLNode &after = tmap->get_state();
_session->add_command (new MementoCommand<Temporal::TempoMap> (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<Temporal::TempoPoint&>(tempo), !tempo.ramped());
XMLNode &after = tmap->get_state();
_session->add_command (new MementoCommand<Temporal::TempoMap> (new Temporal::TempoMap::MementoBinder(), &before, &after));

View File

@ -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<Temporal::MusicTimePoint*>(*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<Temporal::MeterPoint*>(*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<Temporal::TempoPoint*>(*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<TempoMarker*> (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<TempoMarker*>(*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<TempoMarker*>(*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<TempoMarker*> (*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<TempoMarker*> (*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<Temporal::TempoPoint&>(tm.tempo()));
}
void
Editor::edit_meter_marker (MeterMarker& mm)
{
edit_meter_section (mm.meter());
edit_meter_section (const_cast<Temporal::MeterPoint&>(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 ();
}

View File

@ -51,6 +51,7 @@
#include "public_editor.h"
#include "utils.h"
#include "rgb_macros.h"
#include "tempo_curve.h"
#include <gtkmm2ext/utils.h>
@ -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;
}

View File

@ -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__ */

View File

@ -44,17 +44,21 @@ PBD::Signal1<void,TempoCurve*> 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 ();
}

View File

@ -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<void,TempoCurve*> 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;
};