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.
This commit is contained in:
Paul Davis 2025-08-19 07:59:06 -06:00 committed by Edgar Aichinger
parent 2079401b6f
commit 230f08b9fd
5 changed files with 45 additions and 59 deletions

View file

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

View file

@ -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,

View file

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

View file

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

View file

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