From 3900537fcf429a8d4938f3597ee6f300fac90b8e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 8 Dec 2020 20:32:20 -0700 Subject: [PATCH] split Beats::round_to_subdivision() into source module Rounding to bar requires access to the tempo map, and we don't want this in the beats.h header --- libs/temporal/beats.cc | 140 +++++++++++++++++++++++++++++++++ libs/temporal/temporal/beats.h | 92 +--------------------- libs/temporal/wscript | 1 + 3 files changed, 142 insertions(+), 91 deletions(-) create mode 100644 libs/temporal/beats.cc diff --git a/libs/temporal/beats.cc b/libs/temporal/beats.cc new file mode 100644 index 0000000000..69948d73d6 --- /dev/null +++ b/libs/temporal/beats.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2017-2020 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "temporal/beats.h" +#include "temporal/tempo.h" + +using namespace Temporal; + +Beats +Beats::round_to_subdivision (int subdivision, RoundMode dir) const { + + if (subdivision == 0) { + /* do not round */ + return *this; + } + + if (subdivision < 0) { + + /* round to bar */ + + TempoMap::SharedPtr map (TempoMap::use()); + const TempoMetric metric (map->metric_at (*this)); + BBT_Time bbt (metric.bbt_at (*this)); + + if (dir < 0) { + bbt = metric.meter().round_down_to_bar (bbt); + } if (dir > 0) { + bbt = metric.meter().round_up_to_bar (bbt); + } else { + bbt = metric.meter().round_to_bar (bbt); + } + + return metric.quarters_at (bbt); + } + + uint32_t ticks = to_ticks(); + const uint32_t ticks_one_subdivisions_worth = ticks_per_beat / subdivision; + uint32_t mod = ticks % ticks_one_subdivisions_worth; + uint32_t beats = _beats; + + if (dir > 0) { + + if (mod == 0 && dir == RoundUpMaybe) { + /* right on the subdivision, which is fine, so do nothing */ + + } else if (mod == 0) { + /* right on the subdivision, so the difference is just the subdivision ticks */ + ticks += ticks_one_subdivisions_worth; + + } else { + /* not on subdivision, compute distance to next subdivision */ + + ticks += ticks_one_subdivisions_worth - mod; + } + + // NOTE: this code intentionally limits the rounding so we don't advance to the next beat. + // For the purposes of "jump-to-next-subdivision", we DO want to advance to the next beat. + // And since the "prev" direction DOES move beats, I assume this code is unintended. + // But I'm keeping it around, until we determine there are no terrible consequences. + // if (ticks >= Temporal::ticks_per_beat) { + // ticks -= Temporal::ticks_per_beat; + // } + + } else if (dir < 0) { + + /* round to previous (or same iff dir == RoundDownMaybe) */ + + uint32_t difference = ticks % ticks_one_subdivisions_worth; + + if (difference == 0 && dir == RoundDownAlways) { + /* right on the subdivision, but force-rounding down, + so the difference is just the subdivision ticks */ + difference = ticks_one_subdivisions_worth; + } + + if (ticks < difference) { + ticks = ticks_per_beat - ticks; + } else { + ticks -= difference; + } + + } else { + /* round to nearest */ + double rem; + + /* compute the distance to the previous and next subdivision */ + + if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) { + + /* closer to the next subdivision, so shift forward */ + + ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem)); + + //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks)); + + if (ticks > ticks_per_beat) { + ++beats; + ticks -= ticks_per_beat; + //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats)); + } + + } else if (rem > 0) { + + /* closer to previous subdivision, so shift backward */ + + if (rem > ticks) { + if (beats == 0) { + /* can't go backwards past zero, so ... */ + return *this; + } + /* step back to previous beat */ + --beats; + ticks = lrint (ticks_per_beat - rem); + //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats)); + } else { + ticks = lrint (ticks - rem); + //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks)); + } + } else { + /* on the subdivision, do nothing */ + } + } + + return Beats::ticks (ticks); +} diff --git a/libs/temporal/temporal/beats.h b/libs/temporal/temporal/beats.h index 26efcef8a4..e27358cb27 100644 --- a/libs/temporal/temporal/beats.h +++ b/libs/temporal/temporal/beats.h @@ -181,97 +181,7 @@ public: return Beats (_beats+1, 0); } - Beats round_to_subdivision (int subdivision, RoundMode dir) const { - uint32_t ticks = to_ticks(); - const uint32_t ticks_one_subdivisions_worth = ticks_per_beat / subdivision; - uint32_t mod = ticks % ticks_one_subdivisions_worth; - uint32_t beats = _beats; - - if (dir > 0) { - - if (mod == 0 && dir == RoundUpMaybe) { - /* right on the subdivision, which is fine, so do nothing */ - - } else if (mod == 0) { - /* right on the subdivision, so the difference is just the subdivision ticks */ - ticks += ticks_one_subdivisions_worth; - - } else { - /* not on subdivision, compute distance to next subdivision */ - - ticks += ticks_one_subdivisions_worth - mod; - } - - // NOTE: this code intentionally limits the rounding so we don't advance to the next beat. - // For the purposes of "jump-to-next-subdivision", we DO want to advance to the next beat. - // And since the "prev" direction DOES move beats, I assume this code is unintended. - // But I'm keeping it around, until we determine there are no terrible consequences. - // if (ticks >= Temporal::ticks_per_beat) { - // ticks -= Temporal::ticks_per_beat; - // } - - } else if (dir < 0) { - - /* round to previous (or same iff dir == RoundDownMaybe) */ - - uint32_t difference = ticks % ticks_one_subdivisions_worth; - - if (difference == 0 && dir == RoundDownAlways) { - /* right on the subdivision, but force-rounding down, - so the difference is just the subdivision ticks */ - difference = ticks_one_subdivisions_worth; - } - - if (ticks < difference) { - ticks = ticks_per_beat - ticks; - } else { - ticks -= difference; - } - - } else { - /* round to nearest */ - double rem; - - /* compute the distance to the previous and next subdivision */ - - if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) { - - /* closer to the next subdivision, so shift forward */ - - ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem)); - - //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks)); - - if (ticks > ticks_per_beat) { - ++beats; - ticks -= ticks_per_beat; - //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats)); - } - - } else if (rem > 0) { - - /* closer to previous subdivision, so shift backward */ - - if (rem > ticks) { - if (beats == 0) { - /* can't go backwards past zero, so ... */ - return *this; - } - /* step back to previous beat */ - --beats; - ticks = lrint (ticks_per_beat - rem); - //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats)); - } else { - ticks = lrint (ticks - rem); - //DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks)); - } - } else { - /* on the subdivision, do nothing */ - } - } - - return Beats::ticks (ticks); - } + Beats round_to_subdivision (int subdivision, RoundMode dir) const; Beats snap_to (Temporal::Beats const & snap) const { const double snap_time = snap.to_double(); diff --git a/libs/temporal/wscript b/libs/temporal/wscript index f32f34e4eb..a7df9b8dc0 100644 --- a/libs/temporal/wscript +++ b/libs/temporal/wscript @@ -27,6 +27,7 @@ I18N_PACKAGE = 'libtemporal' temporal_sources = [ 'debug.cc', 'bbt_time.cc', + 'beats.cc', 'enums.cc', 'range.cc', 'superclock.cc',