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
This commit is contained in:
parent
0d15797499
commit
3900537fcf
140
libs/temporal/beats.cc
Normal file
140
libs/temporal/beats.cc
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -181,97 +181,7 @@ public:
|
||||||
return Beats (_beats+1, 0);
|
return Beats (_beats+1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Beats round_to_subdivision (int subdivision, RoundMode dir) const {
|
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 snap_to (Temporal::Beats const & snap) const {
|
Beats snap_to (Temporal::Beats const & snap) const {
|
||||||
const double snap_time = snap.to_double();
|
const double snap_time = snap.to_double();
|
||||||
|
|
|
@ -27,6 +27,7 @@ I18N_PACKAGE = 'libtemporal'
|
||||||
temporal_sources = [
|
temporal_sources = [
|
||||||
'debug.cc',
|
'debug.cc',
|
||||||
'bbt_time.cc',
|
'bbt_time.cc',
|
||||||
|
'beats.cc',
|
||||||
'enums.cc',
|
'enums.cc',
|
||||||
'range.cc',
|
'range.cc',
|
||||||
'superclock.cc',
|
'superclock.cc',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user