From 4b28ca21369c41868dd6ca35d0ce8ccd031013ae Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 2 Sep 2025 11:03:38 -0600 Subject: [PATCH] move minsec-ruler related code and variables from Editor to EditingContext --- gtk2_ardour/editing_context.cc | 284 +++++++++++++++++++++++++++++++++ gtk2_ardour/editing_context.h | 24 ++- gtk2_ardour/editor.cc | 3 - gtk2_ardour/editor.h | 13 -- gtk2_ardour/editor_rulers.cc | 31 ---- 5 files changed, 307 insertions(+), 48 deletions(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 75903f4db5..c5182fe2d4 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -178,6 +178,9 @@ EditingContext::EditingContext (std::string const & name) , clear_entered_track (false) , grid_lines (nullptr) , time_line_group (nullptr) + , minsec_mark_interval (0) + , minsec_mark_modulo (0) + , minsec_nmarks (0) , temporary_zoom_focus_change (false) , _dragging_playhead (false) @@ -3591,3 +3594,284 @@ EditingContext::center_screen_internal (samplepos_t sample, float page) reset_x_origin (sample); } + +void +EditingContext::sample_to_clock_parts (samplepos_t sample, + samplepos_t sample_rate, + long* hrs_p, + long* mins_p, + long* secs_p, + long* millisecs_p) +{ + samplepos_t left; + long hrs; + long mins; + long secs; + long millisecs; + + left = sample; + hrs = left / (sample_rate * 60 * 60 * 1000); + left -= hrs * sample_rate * 60 * 60 * 1000; + mins = left / (sample_rate * 60 * 1000); + left -= mins * sample_rate * 60 * 1000; + secs = left / (sample_rate * 1000); + left -= secs * sample_rate * 1000; + millisecs = left / sample_rate; + + *millisecs_p = millisecs; + *secs_p = secs; + *mins_p = mins; + *hrs_p = hrs; + + return; +} + + + +void +EditingContext::metric_get_minsec (std::vector& marks, int64_t lower, int64_t upper, gint /*maxchars*/) +{ + EC_LOCAL_TEMPO_SCOPE; + + samplepos_t pos; + samplepos_t spacer; + long hrs, mins, secs, millisecs; + gchar buf[16]; + gint n; + ArdourCanvas::Ruler::Mark mark; + + if (_session == 0) { + return; + } + + /* to prevent 'flashing' */ + if (lower > (spacer = (samplepos_t) (128 * get_current_zoom ()))) { + lower = lower - spacer; + } else { + lower = 0; + } + + if (minsec_mark_interval == 0) { //we got here too early; divide-by-zero imminent + return; + } + + pos = (((1000 * (samplepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval; + + switch (minsec_ruler_scale) { + + case minsec_show_msecs: + for (n = 0; n < minsec_nmarks && n < upper; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, _session->sample_rate(), &hrs, &mins, &secs, &millisecs); + if (millisecs % minsec_mark_modulo == 0) { + if (millisecs == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); + } else { + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + + case minsec_show_seconds: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, _session->sample_rate(), &hrs, &mins, &secs, &millisecs); + if (secs % minsec_mark_modulo == 0) { + if (secs == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld", hrs, mins, secs); + } else { + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + + case minsec_show_minutes: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, _session->sample_rate(), &hrs, &mins, &secs, &millisecs); + if (mins % minsec_mark_modulo == 0) { + if (mins == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld", hrs, mins, secs); + } else { + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + + case minsec_show_hours: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, _session->sample_rate(), &hrs, &mins, &secs, &millisecs); + if (hrs % minsec_mark_modulo == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + snprintf (buf, sizeof(buf), "%02ld:%02ld", hrs, mins); + } else { + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + + case minsec_show_many_hours: + for (n = 0; n < minsec_nmarks;) { + sample_to_clock_parts (pos, _session->sample_rate(), &hrs, &mins, &secs, &millisecs); + if (hrs % minsec_mark_modulo == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + snprintf (buf, sizeof(buf), "%02ld:00", hrs); + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + ++n; + } + pos += minsec_mark_interval; + } + break; + } +} + +void +EditingContext::set_minsec_ruler_scale (samplepos_t lower, samplepos_t upper) +{ + EC_LOCAL_TEMPO_SCOPE; + + samplepos_t fr = _session->sample_rate() * 1000; + samplepos_t spacer; + + if (_session == 0) { + return; + } + + + /* to prevent 'flashing' */ + if (lower > (spacer = (samplepos_t)(128 * get_current_zoom ()))) { + lower -= spacer; + } else { + lower = 0; + } + upper += spacer; + samplecnt_t const range = (upper - lower) * 1000; + + if (range <= (fr / 10)) { /* 0-0.1 second */ + minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */ + minsec_ruler_scale = minsec_show_msecs; + minsec_mark_modulo = 10; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= (fr / 2)) { /* 0-0.5 second */ + minsec_mark_interval = fr / 100; /* show 1/100 seconds */ + minsec_ruler_scale = minsec_show_msecs; + minsec_mark_modulo = 100; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= fr) { /* 0-1 second */ + minsec_mark_interval = fr / 10; /* show 1/10 seconds */ + minsec_ruler_scale = minsec_show_msecs; + minsec_mark_modulo = 200; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 2 * fr) { /* 1-2 seconds */ + minsec_mark_interval = fr / 10; /* show 1/10 seconds */ + minsec_ruler_scale = minsec_show_msecs; + minsec_mark_modulo = 500; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 8 * fr) { /* 2-5 seconds */ + minsec_mark_interval = fr / 5; /* show 2 seconds */ + minsec_ruler_scale = minsec_show_msecs; + minsec_mark_modulo = 1000; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 16 * fr) { /* 8-16 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 2; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 30 * fr) { /* 10-30 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 60 * fr) { /* 30-60 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */ + minsec_mark_interval = 5 * fr; /* show 5 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 3; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 4 * 60 * fr) { /* 4 minutes */ + minsec_mark_interval = 5 * fr; /* show 10 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 30; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 10 * 60 * fr) { /* 10 minutes */ + minsec_mark_interval = 30 * fr; /* show 30 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 120; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */ + minsec_mark_interval = 60 * fr; /* show 1 minute */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */ + minsec_mark_interval = 2 * 60 * fr; /* show 2 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 10; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/ + minsec_mark_interval = 5 * 60 * fr; /* show 10 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 30; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/ + minsec_mark_interval = 20 * 60 * fr; /* show 20 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 60; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/ + minsec_mark_interval = 60 * 60 * fr; /* show 60 minutes */ + minsec_ruler_scale = minsec_show_hours; + minsec_mark_modulo = 2; + minsec_nmarks = 2 + (range / minsec_mark_interval); + } else { + + const samplecnt_t hours_in_range = range / (60 * 60 * fr); + const int text_width_rough_guess = 70; /* pixels, very very approximate guess at how wide the tick mark text is */ + + /* Normally we do not need to know anything about the width of the canvas + to set the ruler scale, because the caller has already determined + the width and set lower + upper arguments to this function to match that. + + But in this case, where the range defined by lower and upper can vary + substantially (anything from 24hrs+ to several billion years) + trying to decide which tick marks to show does require us to know + about the available width. + */ + + minsec_nmarks = get_canvas()->width() / text_width_rough_guess; + minsec_mark_modulo = std::max ((samplecnt_t) 1, 1 + (hours_in_range / minsec_nmarks)); + minsec_mark_interval = minsec_mark_modulo * (60 * 60 * fr); + minsec_ruler_scale = minsec_show_many_hours; + } +} diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index ca5e371430..3b4abb2d1e 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -780,7 +780,29 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, virtual void metric_get_timecode (std::vector&, int64_t, int64_t, gint) {} virtual void metric_get_bbt (std::vector&, int64_t, int64_t, gint) {} virtual void metric_get_samples (std::vector&, int64_t, int64_t, gint) {} - virtual void metric_get_minsec (std::vector&, int64_t, int64_t, gint) {} + + enum MinsecRulerScale { + minsec_show_msecs, + minsec_show_seconds, + minsec_show_minutes, + minsec_show_hours, + minsec_show_many_hours + }; + + MinsecRulerScale minsec_ruler_scale; + + samplecnt_t minsec_mark_interval; + gint minsec_mark_modulo; + gint minsec_nmarks; + + void metric_get_minsec (std::vector&, int64_t, int64_t, gint); + void set_minsec_ruler_scale (samplepos_t lower, samplepos_t upper); + void sample_to_clock_parts (samplepos_t sample, + samplepos_t sample_rate, + long* hrs_p, + long* mins_p, + long* secs_p, + long* millisecs_p); virtual void set_entered_track (TimeAxisView*) {}; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index d212ea3d2c..f81740a10b 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -257,9 +257,6 @@ Editor::Editor () , no_ruler_shown_update (false) , ruler_grabbed_widget (nullptr) , ruler_dialog (nullptr) - , minsec_mark_interval (0) - , minsec_mark_modulo (0) - , minsec_nmarks (0) , timecode_ruler_scale (timecode_show_many_hours) , timecode_mark_modulo (0) , timecode_nmarks (0) diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index e92455af43..565adaec65 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -875,19 +875,6 @@ private: void restore_ruler_visibility (); void show_rulers_for_grid (); - enum MinsecRulerScale { - minsec_show_msecs, - minsec_show_seconds, - minsec_show_minutes, - minsec_show_hours, - minsec_show_many_hours - }; - - MinsecRulerScale minsec_ruler_scale; - - samplecnt_t minsec_mark_interval; - gint minsec_mark_modulo; - gint minsec_nmarks; void set_minsec_ruler_scale (samplepos_t, samplepos_t); enum TimecodeRulerScale { diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc index 196a663160..c333215570 100644 --- a/gtk2_ardour/editor_rulers.cc +++ b/gtk2_ardour/editor_rulers.cc @@ -1296,37 +1296,6 @@ Editor::metric_get_samples (std::vector& marks, int64 } } -static void -sample_to_clock_parts (samplepos_t sample, - samplepos_t sample_rate, - long* hrs_p, - long* mins_p, - long* secs_p, - long* millisecs_p) -{ - samplepos_t left; - long hrs; - long mins; - long secs; - long millisecs; - - left = sample; - hrs = left / (sample_rate * 60 * 60 * 1000); - left -= hrs * sample_rate * 60 * 60 * 1000; - mins = left / (sample_rate * 60 * 1000); - left -= mins * sample_rate * 60 * 1000; - secs = left / (sample_rate * 1000); - left -= secs * sample_rate * 1000; - millisecs = left / sample_rate; - - *millisecs_p = millisecs; - *secs_p = secs; - *mins_p = mins; - *hrs_p = hrs; - - return; -} - void Editor::set_minsec_ruler_scale (samplepos_t lower, samplepos_t upper) {