From 230f08b9fd0418e2f0b0c48f7c8c669c6f91c6f3 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 19 Aug 2025 07:59:06 -0600 Subject: [PATCH] temporal: BBT_Time cannot have any round_to_*() or round_up_to_*() methods A meter (time signature) is required to do the math correctly for any operation that may cross or reach the next bar boundary, which round_to_*() and round_up_to_*() may do. --- libs/ardour/session_transport.cc | 3 +- libs/temporal/bbt_time.cc | 33 ------------------ libs/temporal/beats.cc | 2 +- libs/temporal/tempo.cc | 56 +++++++++++++++++++++---------- libs/temporal/temporal/bbt_time.h | 10 ++---- 5 files changed, 45 insertions(+), 59 deletions(-) diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 7938daf323..b3d39c920c 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -2210,7 +2210,8 @@ Session::flush_cue_recording () while (TriggerBox::cue_records.read (&cr, 1) == 1) { BBT_Argument bbt = tmap->bbt_at (timepos_t (cr.when)); - bbt = BBT_Argument (bbt.reference(), bbt.round_up_to_bar ()); + Meter const & meter (tmap->meter_at (timepos_t (cr.when))); + bbt = BBT_Argument (bbt.reference(), meter.round_up_to_bar (bbt)); const timepos_t when (tmap->quarters_at (bbt)); diff --git a/libs/temporal/bbt_time.cc b/libs/temporal/bbt_time.cc index d0ae043304..13eaac6926 100644 --- a/libs/temporal/bbt_time.cc +++ b/libs/temporal/bbt_time.cc @@ -42,39 +42,6 @@ BBT_Time::from_integer (int64_t v) return BBT_Time (B, b, t); } -BBT_Time -BBT_Time::round_up_to_bar() const -{ - if (ticks == 0 && beats == 1) { - return *this; - } - BBT_Time b = round_up_to_beat (); - if (b.beats > 1) { - b.bars += 1; - b.beats = 1; - } - return b; -} - -BBT_Time -BBT_Time::round_up_to_beat_div (int beat_div) const -{ - /* XXX this doesn't work where "beats" are not quarters, because - we could have B|b|0 and this is not on a beat_div, even though it is - an integer beat position (think triplets. - */ - - const int32_t div_ticks = ticks_per_beat / beat_div; - int32_t rounded_up = ticks + div_ticks - 1; - rounded_up -= rounded_up % div_ticks; - - if (rounded_up == ticks_per_beat) { - return BBT_Time (bars, beats+1, 0); - } - - return BBT_Time (bars, beats, rounded_up); -} - BBT_Offset::BBT_Offset (double dbeats) { /* NOTE: this does not construct a BBT time in a canonical form, diff --git a/libs/temporal/beats.cc b/libs/temporal/beats.cc index fb3d594e80..5986adab5a 100644 --- a/libs/temporal/beats.cc +++ b/libs/temporal/beats.cc @@ -54,7 +54,7 @@ Beats::round_to_subdivision (int subdivision, RoundMode dir) const { if (dir == RoundUpAlways && bbt.ticks == 0) { bbt.ticks += 1; } - bbt = bbt.round_up_to_bar (); + bbt = metric.meter().round_up_to_bar (bbt); } else { bbt = metric.meter().round_to_bar (bbt); } diff --git a/libs/temporal/tempo.cc b/libs/temporal/tempo.cc index 9a78218dea..3cd120d3b4 100644 --- a/libs/temporal/tempo.cc +++ b/libs/temporal/tempo.cc @@ -353,6 +353,31 @@ Meter::round_to_beat (Temporal::Beats const & b) const return b.round_to_multiple (Beats::ticks (ticks_per_grid())); } +Temporal::BBT_Time +Meter::round_to_beat (Temporal::BBT_Time const & bbt) const +{ + if (bbt.ticks == 0) { + return bbt; + } + + BBT_Time b (bbt); + + if (bbt.ticks >= ticks_per_grid()) { + /* Round up */ + b.ticks = 0; + b.beats += 1; + if (b.beats > _divisions_per_bar) { + b.beats = 0; + b.bars++; + } + } else { + /* Round down */ + b.ticks = 0; + } + + return b; +} + Temporal::BBT_Time Meter::round_to_bar (Temporal::BBT_Time const & bbt) const { @@ -380,23 +405,20 @@ Meter::round_up_to_bar (Temporal::BBT_Time const & bbt) const Temporal::BBT_Time Meter::round_up_to_beat_div (Temporal::BBT_Time const & bbt, int beat_div) const { - Temporal::BBT_Time b = bbt.round_up_to_beat_div (beat_div); - if (b.beats > _divisions_per_bar) { - b.bars++; - b.beats = 1; - } - return b; -} + const int32_t div_ticks = ticks_per_grid() / beat_div; + int32_t rounded_up = bbt.ticks + div_ticks - 1; + rounded_up -= rounded_up % div_ticks; -Temporal::BBT_Time -Meter::round_to_beat (Temporal::BBT_Time const & bbt) const -{ - Temporal::BBT_Time b = bbt.round_to_beat (); - if (b.beats > _divisions_per_bar) { - b.bars++; - b.beats = 1; + if (rounded_up == ticks_per_grid()) { + /* round up next beat count, which may be in next bar */ + if (bbt.beats + 1 > _divisions_per_bar) { + return BBT_Time (bbt.bars+1, 1, 0); + } else { + return BBT_Time (bbt.bars, bbt.beats+1, 0); + } } - return b; + + return BBT_Time (bbt.bars, bbt.beats, rounded_up); } Temporal::Beats @@ -2689,7 +2711,7 @@ TempoMap::get_grid (TempoMapPoints& ret, superclock_t rstart, superclock_t end, if (rstart != 0) { if (bar_mod == 1) { - on_bar = bbt.round_up_to_bar (); + on_bar = metric.meter().round_up_to_bar (bbt); } else { on_bar = metric.meter().round_up_to_beat_div (bbt, beat_div); } @@ -2955,7 +2977,7 @@ TempoMap::fill_grid_by_walking (TempoMapPoints& ret, Points::const_iterator& p_i BBT_Time on_bar; if (bar_mod == 1) { - on_bar = p->bbt().round_up_to_bar (); + on_bar = mp->round_up_to_bar (p->bbt()); } else { on_bar = mp->round_up_to_beat_div (p->bbt(), beat_div); } diff --git a/libs/temporal/temporal/bbt_time.h b/libs/temporal/temporal/bbt_time.h index 4ff1f18f3c..2cccf92c35 100644 --- a/libs/temporal/temporal/bbt_time.h +++ b/libs/temporal/temporal/bbt_time.h @@ -111,19 +111,15 @@ struct LIBTEMPORAL_API BBT_Time * values. */ - BBT_Time round_to_beat () const { return ticks >= (ticks_per_beat/2) ? BBT_Time (bars, beats+1, 0) : BBT_Time (bars, beats, 0); } - BBT_Time round_down_to_beat () const { return BBT_Time (bars, beats, 0); } - BBT_Time round_up_to_beat () const { return ticks ? BBT_Time (bars, beats+1, 0) : *this; } - BBT_Time round_up_to_beat_div (int beat_div) const; - - /* cannot implement round_to_bar() without knowing meter (time + /* cannot implement round_to_*() or round_up_tp_*() without knowing meter (time * signature) information, since it requires knowing how many beats * are in a bar, in order to decide if we are closer to the previous or * next bar time. */ - BBT_Time round_up_to_bar () const; + BBT_Time round_down_to_beat () const { return BBT_Time (bars, beats, 0); } BBT_Time round_down_to_bar () const { return BBT_Time (bars, 1, 0); } + BBT_Time next_bar () const { return (bars == -1) ? BBT_Time (1, 1, 0) : BBT_Time (bars+1, 1, 0); } BBT_Time prev_bar () const { return (bars == 1) ? BBT_Time (-1, 1, 0) : BBT_Time (bars-1, 1, 0); }